Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS>0}"); static final DiagnosticType SHIFT_AMOUNT_OUT_OF_BOUNDS = DiagnosticType.error( "JSC_SHIFT_AMOUNT_OUT_OF_BOUNDS", "Shift amount out of bounds: {0}"); static final DiagnosticType FRACTIONAL_BITWISE_OPERAND = DiagnosticType.error( "JSC_FRACTIONAL_BITWISE_OPERAND", "Fractional bitwise operand: {0}"); private static final double MAX_FOLD_NUMBER = Math.pow(2, 53); // The LOCALE independent "locale" private static final Locale ROOT_LOCALE = new Locale(""); @Override Node optimizeSubtree(Node subtree) { switch(subtree.getType()) { case Token.CALL: return tryFoldKnownMethods(subtree); case Token.NEW: return tryFoldCtorCall(subtree); case Token.TYPEOF: return tryFoldTypeof(subtree); case Token.NOT: case Token.POS: case Token.NEG: case Token.BITNOT: tryReduceOperandsForOp(subtree); return tryFoldUnaryOperator(subtree); case Token.VOID: return tryReduceVoid(subtree); default: tryReduceOperandsForOp(subtree); return tryFoldBinaryOperator(subtree); } } private Node tryFoldBinaryOperator(Node subtree) { Node left = subtree.getFirstChild(); if (left == null) { return subtree; } Node right = left.getNext(); if (right == null) { return subtree; } // If we've reached here, node is truly a binary operator. switch(subtree.getType()) { case Token.GETPROP: return tryFoldGetProp(subtree, left, right); case Token.GETELEM: return tryFoldGetElem(subtree, left, right); case Token.INSTANCEOF: return tryFoldInstanceof(subtree, left, right); case Token.AND: case Token.OR: return tryFoldAndOr(subtree, left, right); case Token.LSH: case Token.RSH: case Token.URSH: return tryFoldShift(subtree, left, right); case Token.ASSIGN: return tryFold

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS>AND: case Token.LSH: case Token.RSH: case Token.URSH: case Token.SUB: case Token.MUL: case Token.MOD: case Token.DIV: case Token.POS: case Token.NEG: tryConvertOperandsToNumber(n); break; } } private void tryConvertOperandsToNumber(Node n) { Node next; for (Node c = n.getFirstChild(); c != null; c = next) { next = c.getNext(); tryConvertToNumber(c); } } private void tryConvertToNumber(Node n) { switch (n.getType()) { case Token.NUMBER: // Nothing to do return; case Token.AND: case Token.OR: case Token.COMMA: tryConvertToNumber(n.getLastChild()); return; case Token.HOOK: tryConvertToNumber(n.getChildAtIndex(1)); tryConvertToNumber(n.getLastChild()); return; case Token.NAME: if (!NodeUtil.isUndefined(n)) { return; } break; } Double result = NodeUtil.getNumberValue(n); if (result == null) { return; } double value = result; Node replacement; if (Double.isNaN(value)) { replacement = Node.newString(Token.NAME, "NaN"); } else if (value == Double.POSITIVE_INFINITY) { replacement = Node.newString(Token.NAME, "Infinity"); } else if (value == Double.NEGATIVE_INFINITY) { replacement = new Node(Token.NEG, Node.newString(Token.NAME, "Infinity")); replacement.copyInformationFromForTree(n); } else { replacement = Node.newNumber(value); } n.getParent().replaceChild(n, replacement); reportCodeChange(); } /** * Folds 'typeof(foo)' if foo is a literal, e.g. * typeof("bar") --> "string" * typeof(6) --> "number" */ private Node tryFoldTypeof(Node originalTypeofNode) { Preconditions.checkArgument(originalTypeofNode.getType() == Token.TYPEOF); Node argumentNode = originalTypeofNode.

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS>getFirstChild(); if (argumentNode == null || !NodeUtil.isLiteralValue(argumentNode, true)) { return originalTypeofNode; } String typeNameString = null; switch (argumentNode.getType()) { case Token.FUNCTION: typeNameString = "function"; break; case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; case Token.VOID: typeNameString = "undefined"; break; case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); return newNode; } return originalTypeofNode; } private Node tryFoldUnaryOperator(Node n) { Preconditions.checkState(n.hasOneChild()); Node left = n.getFirstChild(); Node parent = n.getParent(); if (left == null) { return n; } TernaryValue leftVal = NodeUtil.getPureBooleanValue(left); if (leftVal == TernaryValue.UNKNOWN) { return n; } switch (n.getType()) { case Token.NOT: // Don't fold !0 and !1 back to false. if (left.getType() == Token.NUMBER) { double numValue = left.getDouble(); if (numValue == 0 || numValue == 1) { return n; } } int result = leftVal.toBoolean(true) ? Token.FALSE : Token.TRUE; Node replacementNode = new Node(result); parent.replaceChild(n, replacementNode); reportCodeChange(); return replacementNode; case Token.POS: if (NodeUtil.is

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS>; case Token.MOD: newType = Token.ASSIGN_MOD; break; case Token.MUL: newType = Token.ASSIGN_MUL; break; case Token.RSH: newType = Token.ASSIGN_RSH; break; case Token.SUB: newType = Token.ASSIGN_SUB; break; case Token.URSH: newType = Token.ASSIGN_URSH; break; default: return n; } Node newNode = new Node(newType, left.detachFromParent(), newRight.detachFromParent()); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * Try to fold a AND/OR node. */ private Node tryFoldAndOr(Node n, Node left, Node right) { Node parent = n.getParent(); Node result = null; int type = n.getType(); TernaryValue leftVal = NodeUtil.getImpureBooleanValue(left); if (leftVal != TernaryValue.UNKNOWN) { boolean lval = leftVal.toBoolean(true); // (TRUE || x) => TRUE (also, (3 || x) => 3) // (FALSE && x) => FALSE if (lval && type == Token.OR || !lval && type == Token.AND) { result = left; } else if (!mayHaveSideEffects(left)) { // (FALSE || x) => x // (TRUE && x) => x result = right; } } // Note: Right hand side folding is handled by // PeepholeSubstituteAlternateSyntax#tryMinimizeCondition if (result != null) { // Fold it! n.removeChild(result); parent.replaceChild(n, result); reportCodeChange(); return result; } else { return n; } } /** * Expressions such as [foo() + 'a' + 'b'] generate parse trees * where no node has two const children ((foo() + 'a') + 'b'), so * tryFoldAdd() won't fold it -- tryFoldLeftChildAdd() will (for Strings). * Specifically it folds Add exprssions where: *

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS> value The value to compare to "undefined" * @param op The boolean op to compare with * @return Whether the boolean op is true or false */ private boolean compareToUndefined(Node value, int op) { boolean valueUndefined = ((Token.NAME == value.getType() && value.getString().equals("undefined")) || (Token.VOID == value.getType() && NodeUtil.isLiteralValue(value.getFirstChild(), false))); boolean valueNull = (Token.NULL == value.getType()); boolean equivalent = valueUndefined || valueNull; switch (op) { case Token.EQ: // undefined is only equal to null or an undefined value return equivalent; case Token.NE: return !equivalent; case Token.SHEQ: return valueUndefined; case Token.SHNE: return !valueUndefined; case Token.LT: case Token.GT: case Token.LE: case Token.GE: return false; default: throw new IllegalStateException("unexpected."); } } /** * Try to fold away unnecessary object instantiation. * e.g. this[new String('eval')] -> this.eval */ private Node tryFoldCtorCall(Node n) { Preconditions.checkArgument(n.getType() == Token.NEW); // we can remove this for GETELEM calls (anywhere else?) if (inForcedStringContext(n)) { return tryFoldInForcedStringContext(n); } return n; } /** Returns whether this node must be coerced to a string. */ private boolean inForcedStringContext(Node n) { return n.getParent().getType() == Token.GETELEM && n.getParent().getLastChild() == n; } private Node tryFoldInForcedStringContext(Node n) { // For now, we only know how to fold ctors. Preconditions.checkArgument(n.getType() == Token.NEW); Node objectType = n.getFirstChild(); if (objectType.getType() != Token.NAME) { return n; } if (objectType.getString().equals("String")) { Node value = objectType.getNext(); String stringValue = null; if (value == null) { stringValue = ""; } else { if

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS> (!NodeUtil.isImmutableValue(value)) { return n; } stringValue = NodeUtil.getStringValue(value); } if (stringValue == null) { return n; } Node parent = n.getParent(); Node newString = Node.newString(stringValue); parent.replaceChild(n, newString); newString.copyInformationFrom(parent); reportCodeChange(); return newString; } return n; } private Node tryFoldKnownMethods(Node subtree) { // For now we only support .join(), // .indexOf(), .substring() and .substr() subtree = tryFoldArrayJoin(subtree); if (subtree.getType() == Token.CALL) { subtree = tryFoldKnownStringMethods(subtree); } return subtree; } /** * Try to eveluate known String methods * .indexOf(), .substr(), .substring() */ private Node tryFoldKnownStringMethods(Node subtree) { Preconditions.checkArgument(subtree.getType() == Token.CALL); // check if this is a call on a string method // then dispatch to specific folding method. Node callTarget = subtree.getFirstChild(); if (callTarget == null) { return subtree; } if (!NodeUtil.isGet(callTarget)) { return subtree; } Node stringNode = callTarget.getFirstChild(); Node functionName = stringNode.getNext(); if ((stringNode.getType() != Token.STRING) || ( (functionName.getType() != Token.STRING))) { return subtree; } String functionNameString = functionName.getString(); Node firstArg = callTarget.getNext(); if (firstArg == null) { if (functionNameString.equals("toLowerCase")) { subtree = tryFoldStringToLowerCase(subtree, stringNode); } else if (functionNameString.equals("toUpperCase")) { subtree = tryFoldStringToUpperCase(subtree, stringNode); } return subtree; } else if (NodeUtil.isImmutableValue(firstArg)) { if (functionNameString.equals("indexOf") || functionNameString.equals("lastIndexOf")) { subtree = tryFoldStringIndexOf(subtree, functionNameString, stringNode, firstArg); } else if

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS> here: // "{a:x}.a += 1" is not "x += 1" return n; } // find the last definition in the object literal Node key = null; Node value = null; for (Node c = left.getFirstChild(); c != null; c = c.getNext()) { if (c.getString().equals(right.getString())) { switch (c.getType()) { case Token.SET: continue; case Token.GET: case Token.STRING: if (value != null && mayHaveSideEffects(value)) { // The previously found value had side-effects return n; } key = c; value = key.getFirstChild(); break; default: throw new IllegalStateException(); } } else if (mayHaveSideEffects(c.getFirstChild())) { // We don't handle the side-effects here as they might need a temporary // or need to be reordered. return n; } } // Didn't find a definition of the name in the object literal, it might // be coming from the Object prototype if (value == null) { return n; } if (value.getType() == Token.FUNCTION && NodeUtil.referencesThis(value)) { // 'this' may refer to the object we are trying to remove return n; } Node replacement = value.detachFromParent(); if (key.getType() == Token.GET){ replacement = new Node(Token.CALL, replacement); } n.getParent().replaceChild(n, replacement); reportCodeChange(); return n; } }

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS> void endCaseBody() { super.endCaseBody(); indent--; endStatement(); } @Override void appendOp(String op, boolean binOp) { if (binOp) { if (getLastChar() != ' ') { append(" "); } append(op); append(" "); } else { append(op); } } /** * If the body of a for loop or the then clause of an if statement has * a single statement, should it be wrapped in a block? * {@inheritDoc} */ @Override boolean shouldPreserveExtraBlocks() { // When pretty-printing, always place the statement in its own block // so it is printed on a separate line. This allows breakpoints to be // placed on the statement. return true; } /** * @return The TRY node for the specified CATCH node. */ private Node getTryForCatch(Node n) { return n.getParent().getParent(); } /** * @return Whether the a line break should be added after the specified * BLOCK. */ @Override boolean breakAfterBlockFor(Node n, boolean isStatementContext) { Preconditions.checkState(n.getType() == Token.BLOCK); Node parent = n.getParent(); if (parent != null) { int type = parent.getType(); switch (type) { case Token.DO: // Don't break before 'while' in DO-WHILE statements. return false; case Token.FUNCTION: // FUNCTIONs are handled separately, don't break here. return false; case Token.TRY: // Don't break before catch return n != parent.getFirstChild(); case Token.CATCH: // Don't break before finally return !NodeUtil.hasFinally(getTryForCatch(parent)); case Token.IF: // Don't break before else return n == parent.getLastChild(); } } return true; } @Override void endFile() { maybeEndStatement(); } } static class CompactCodePrinter extends MappedCodePrinter { // The CompactCodePrinter tries to emit just enough newlines to stop there // being lines longer than the threshold. Since the output is going to be // gzipped,

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS> return caseEquality(condition, blindScope, EQ); } case Token.SHEQ: if (outcome) { return caseEquality(condition, blindScope, SHEQ); } else { return caseEquality(condition, blindScope, SHNE); } case Token.SHNE: if (outcome) { return caseEquality(condition, blindScope, SHNE); } else { return caseEquality(condition, blindScope, SHEQ); } case Token.NAME: case Token.GETPROP: return caseNameOrGetProp(condition, blindScope, outcome); case Token.ASSIGN: return firstPreciserScopeKnowingConditionOutcome( condition.getFirstChild(), firstPreciserScopeKnowingConditionOutcome( condition.getFirstChild().getNext(), blindScope, outcome), outcome); case Token.NOT: return firstPreciserScopeKnowingConditionOutcome( condition.getFirstChild(), blindScope, !outcome); case Token.LE: case Token.LT: case Token.GE: case Token.GT: if (outcome) { return caseEquality(condition, blindScope, INEQ); } break; case Token.INSTANCEOF: return caseInstanceOf( condition.getFirstChild(), condition.getLastChild(), blindScope, outcome); case Token.IN: if (outcome && condition.getFirstChild().getType() == Token.STRING) { return caseIn(condition.getLastChild(), condition.getFirstChild().getString(), blindScope); } break; case Token.CASE: Node left = condition.getParent().getFirstChild(); // the switch condition Node right = condition.getFirstChild(); if (outcome) { return caseEquality(left, right, blindScope, SHEQ); } else { return caseEquality(left, right, blindScope, SHNE); } } return nextPreciserScopeKnowingConditionOutcome( condition, blindScope, outcome); } private FlowScope caseEquality(Node condition, FlowScope blindScope, Function<TypePair, TypePair> merging) { return caseEquality(condition.getFirstChild(), condition.getLastChild(), blindScope, merging); } private FlowScope caseEquality(Node left, Node right, FlowScope blindScope, Function<Type

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS> getTypeIfRefinable(right, blindScope); boolean rightIsRefineable; if (rightType != null) { rightIsRefineable = true; } else { rightIsRefineable = false; rightType = right.getJSType(); blindScope = firstPreciserScopeKnowingConditionOutcome( right, blindScope, condition); } if (condition) { rightType = (rightType == null) ? null : rightType.getRestrictedTypeGivenToBooleanOutcome(condition); // creating new scope if ((leftType != null && leftIsRefineable) || (rightType != null && rightIsRefineable)) { FlowScope informed = blindScope.createChildFlowScope(); if (leftIsRefineable && leftType != null) { declareNameInScope(informed, left, leftType); } if (rightIsRefineable && rightType != null) { declareNameInScope(informed, right, rightType); } return informed; } } return blindScope; } private FlowScope caseAndOrMaybeShortCircuiting(Node left, Node right, FlowScope blindScope, boolean condition) { FlowScope leftScope = firstPreciserScopeKnowingConditionOutcome( left, blindScope, !condition); StaticSlot<JSType> leftVar = leftScope.findUniqueRefinedSlot(blindScope); if (leftVar == null) { return blindScope; } FlowScope rightScope = firstPreciserScopeKnowingConditionOutcome( left, blindScope, condition); rightScope = firstPreciserScopeKnowingConditionOutcome( right, rightScope, !condition); StaticSlot<JSType> rightVar = rightScope.findUniqueRefinedSlot(blindScope); if (rightVar == null || !leftVar.getName().equals(rightVar.getName())) { return blindScope; } JSType type = leftVar.getType().getLeastSupertype(rightVar.getType()); FlowScope informed = blindScope.createChildFlowScope(); informed.inferSlotType(leftVar.getName(), type); return informed; } private FlowScope caseNameOrGetProp(Node name, FlowScope blindScope, boolean outcome) {

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS> JSType type = getTypeIfRefinable(name, blindScope); if (type != null) { JSType restrictedType = type.getRestrictedTypeGivenToBooleanOutcome(outcome); FlowScope informed = blindScope.createChildFlowScope(); declareNameInScope(informed, name, restrictedType); return informed; } return blindScope; } private FlowScope caseTypeOf(Node node, JSType type, String value, boolean resultEqualsValue, FlowScope blindScope) { JSType restrictedType = getRestrictedByTypeOfResult(type, value, resultEqualsValue); if (restrictedType == null) { return blindScope; } FlowScope informed = blindScope.createChildFlowScope(); declareNameInScope(informed, node, restrictedType); return informed; } private FlowScope caseInstanceOf(Node left, Node right, FlowScope blindScope, boolean outcome) { JSType leftType = getTypeIfRefinable(left, blindScope); if (leftType == null) { return blindScope; } JSType rightType = right.getJSType(); ObjectType targetType = typeRegistry.getNativeObjectType(JSTypeNative.UNKNOWN_TYPE); if (rightType instanceof FunctionType) { targetType = (FunctionType) rightType; } Visitor<JSType> visitor; if (outcome) { visitor = new RestrictByTrueInstanceOfResultVisitor(targetType); } else { visitor = new RestrictByFalseInstanceOfResultVisitor(targetType); } JSType restrictedLeftType = leftType.visit(visitor); if (restrictedLeftType != null && !restrictedLeftType.equals(leftType)) { FlowScope informed = blindScope.createChildFlowScope(); declareNameInScope(informed, left, restrictedLeftType); return informed; } return blindScope; } /** * Given 'property in object', ensures that the object has the property in the * informed scope by defining it as a qualified name if the object type lacks * the property and it's not in the blind scope. * @param object The node of the right-side of the in. * @param propertyName The string of the left-side of the in. */ private FlowScope case

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS>In(Node object, String propertyName, FlowScope blindScope) { JSType jsType = object.getJSType(); jsType = this.getRestrictedWithoutNull(jsType); jsType = this.getRestrictedWithoutUndefined(jsType); boolean hasProperty = false; ObjectType objectType = ObjectType.cast(jsType); if (objectType != null) { hasProperty = objectType.hasProperty(propertyName); } if (!hasProperty) { String qualifiedName = object.getQualifiedName(); if (qualifiedName != null) { String propertyQualifiedName = qualifiedName + "." + propertyName; if (blindScope.getSlot(propertyQualifiedName) == null) { FlowScope informed = blindScope.createChildFlowScope(); JSType unknownType = typeRegistry.getNativeType( JSTypeNative.UNKNOWN_TYPE); informed.inferQualifiedSlot( propertyQualifiedName, unknownType, unknownType); return informed; } } } return blindScope; } /** * @see SemanticReverseAbstractInterpreter#caseInstanceOf */ private class RestrictByTrueInstanceOfResultVisitor extends RestrictByTrueTypeOfResultVisitor { private final ObjectType target; RestrictByTrueInstanceOfResultVisitor(ObjectType target) { this.target = target; } @Override protected JSType caseTopType(JSType type) { return applyCommonRestriction(type); } @Override public JSType caseUnknownType() { if (target instanceof FunctionType) { FunctionType funcTarget = (FunctionType) target; if (funcTarget.hasInstanceType()) { return funcTarget.getInstanceType(); } } return getNativeType(UNKNOWN_TYPE); } @Override public JSType caseObjectType(ObjectType type) { return applyCommonRestriction(type); } @Override public JSType caseUnionType(UnionType type) { return applyCommonRestriction(type); } @Override public JSType caseFunctionType(FunctionType type) { return caseObjectType(type); } private JSType applyCommonRestriction(JSType type) { if (target.isUnknownType()) { return type; } FunctionType funcTarget = (FunctionType) target; if (funcTarget.hasInstanceType()) { return type.getGreatestSubtype(func

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS>Target.getInstanceType()); } return null; } } /** * @see SemanticReverseAbstractInterpreter#caseInstanceOf */ private class RestrictByFalseInstanceOfResultVisitor extends RestrictByFalseTypeOfResultVisitor { private final ObjectType target; RestrictByFalseInstanceOfResultVisitor(ObjectType target) { this.target = target; } @Override public JSType caseObjectType(ObjectType type) { if (target.isUnknownType()) { return type; } FunctionType funcTarget = (FunctionType) target; if (funcTarget.hasInstanceType()) { if (type.isSubtype(funcTarget.getInstanceType())) { return null; } return type; } return null; } @Override public JSType caseUnionType(UnionType type) { if (target.isUnknownType()) { return type; } FunctionType funcTarget = (FunctionType) target; if (funcTarget.hasInstanceType()) { return type.getRestrictedUnion(funcTarget.getInstanceType()); } return null; } @Override public JSType caseFunctionType(FunctionType type) { return caseObjectType(type); } } }

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS>(n2); for (DiGraphEdge<N, E> outEdge : dNode1.getOutEdges()) { if (outEdge.getDestination() == dNode2) { return outEdge; } } for (DiGraphEdge<N, E> outEdge : dNode2.getOutEdges()) { if (outEdge.getDestination() == dNode1) { return outEdge; } } return null; } @Override public GraphNode<N, E> createNode(N value) { return createDirectedGraphNode(value); } @Override public List<DiGraphEdge<N, E>> getDirectedGraphEdges(N n1, N n2) { DiGraphNode<N, E> dNode1 = getNodeOrFail(n1); DiGraphNode<N, E> dNode2 = getNodeOrFail(n2); List<DiGraphEdge<N, E>> edges = Lists.newArrayList(); for (DiGraphEdge<N, E> outEdge : dNode1.getOutEdges()) { if (outEdge.getDestination() == dNode2) { edges.add(outEdge); } } return edges; } @Override public boolean isConnectedInDirection(N n1, N n2) { return isConnectedInDirection(n1, Predicates.<E>alwaysTrue(), n2); } @Override public boolean isConnectedInDirection(N n1, E edgeValue, N n2) { return isConnectedInDirection(n1, Predicates.equalTo(edgeValue), n2); } private boolean isConnectedInDirection(N n1, Predicate<E> edgeMatcher, N n2) { // Verify the nodes. DiGraphNode<N, E> dNode1 = getNodeOrFail(n1); DiGraphNode<N, E> dNode2 = getNodeOrFail(n2); for (DiGraphEdge<N, E> outEdge : dNode1.getOutEdges()) { if (outEdge.getDestination() == dNode2 && edgeMatcher.apply(outEdge.getValue())) { return true; } } return false; } @Override public List<DiGraphNode<N, E>> get

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS> @Override public Collection<GraphNode<N, E>> getNodes() { return Collections.<GraphNode<N, E>>unmodifiableCollection(nodes.values()); } @Override public List<GraphNode<N, E>> getNeighborNodes(N value) { DiGraphNode<N, E> node = getDirectedGraphNode(value); return getNeighborNodes(node); } public List<GraphNode<N, E>> getNeighborNodes(DiGraphNode<N, E> node) { List<GraphNode<N, E>> result = Lists.newArrayList(); for (Iterator<GraphNode<N, E>> i = ((LinkedDirectedGraphNode<N, E>) node).neighborIterator();i.hasNext();) { result.add(i.next()); } return result; } @Override public Iterator<GraphNode<N, E>> getNeighborNodesIterator(N value) { LinkedDirectedGraphNode<N, E> node = nodes.get(value); Preconditions.checkNotNull(node); return node.neighborIterator(); } @Override public List<GraphEdge<N, E>> getEdges() { List<GraphEdge<N, E>> result = Lists.newArrayList(); for (DiGraphNode<N, E> node : nodes.values()) { for (DiGraphEdge<N, E> edge : node.getOutEdges()) { result.add(edge); } } return Collections.unmodifiableList(result); } @Override public int getNodeDegree(N value) { DiGraphNode<N, E> node = getNodeOrFail(value); return node.getInEdges().size() + node.getOutEdges().size(); } /** * A directed graph node that stores outgoing edges and incoming edges as an * list within the node itself. */ static class LinkedDirectedGraphNode<N, E> implements DiGraphNode<N, E>, GraphvizNode { List<DiGraphEdge<N, E>> inEdgeList = Lists.newArrayList(); List<DiGraphEdge<N, E>> outEdgeList = Lists.newArrayList(); protected final N value; /** * Constructor * * @param nodeValue Node's value. */ LinkedDirectedGraphNode(N nodeValue

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS>) { this.value = nodeValue; } @Override public N getValue() { return value; } @Override public <A extends Annotation> A getAnnotation() { throw new UnsupportedOperationException( "Graph initialized with node annotations turned off"); } @Override public void setAnnotation(Annotation data) { throw new UnsupportedOperationException( "Graph initialized with node annotations turned off"); } @Override public String getColor() { return "white"; } @Override public String getId() { return "LDN" + hashCode(); } @Override public String getLabel() { return value != null ? value.toString() : "null"; } @Override public String toString() { return getLabel(); } @Override public List<DiGraphEdge<N, E>> getInEdges() { return inEdgeList; } @Override public List<DiGraphEdge<N, E>> getOutEdges() { return outEdgeList; } private Iterator<GraphNode<N, E>> neighborIterator() { return new NeighborIterator(); } private class NeighborIterator implements Iterator<GraphNode<N, E>> { private final Iterator<DiGraphEdge<N, E>> in = inEdgeList.iterator(); private final Iterator<DiGraphEdge<N, E>> out = outEdgeList.iterator(); @Override public boolean hasNext() { return in.hasNext() || out.hasNext(); } @Override public GraphNode<N, E> next() { boolean isOut = !in.hasNext(); Iterator<DiGraphEdge<N, E>> curIterator = isOut ? out : in; DiGraphEdge<N, E> s = curIterator.next(); return isOut ? s.getDestination() : s.getSource(); } @Override public void remove() { throw new UnsupportedOperationException("Remove not supported."); } } } /** * A directed graph node with annotations. */ static class AnnotatedLinkedDirectedGraphNode<N, E> extends LinkedDirectedGraphNode<N, E> { protected Annotation annotation; /** * @param nodeValue Node's value. */ AnnotatedLinkedDirectedGraphNode(N nodeValue) { super(nodeValue

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS>); } @SuppressWarnings("unchecked") @Override public <A extends Annotation> A getAnnotation() { return (A) annotation; } @Override public void setAnnotation(Annotation data) { annotation = data; } } /** * A directed graph edge that stores the source and destination nodes at each * edge. */ static class LinkedDirectedGraphEdge<N, E> implements DiGraphEdge<N, E>, GraphvizEdge { private DiGraphNode<N, E> sourceNode; private DiGraphNode<N, E> destNode; protected final E value; /** * Constructor. * * @param edgeValue Edge Value. */ LinkedDirectedGraphEdge(DiGraphNode<N, E> sourceNode, E edgeValue, DiGraphNode<N, E> destNode) { this.value = edgeValue; this.sourceNode = sourceNode; this.destNode = destNode; } @Override public DiGraphNode<N, E> getSource() { return sourceNode; } @Override public DiGraphNode<N, E> getDestination() { return destNode; } @Override public void setDestination(DiGraphNode<N, E> node) { destNode = node; } @Override public void setSource(DiGraphNode<N, E> node) { sourceNode = node; } @Override public E getValue() { return value; } @Override public <A extends Annotation> A getAnnotation() { throw new UnsupportedOperationException( "Graph initialized with edge annotations turned off"); } @Override public void setAnnotation(Annotation data) { throw new UnsupportedOperationException( "Graph initialized with edge annotations turned off"); } @Override public String getColor() { return "black"; } @Override public String getLabel() { return value != null ? value.toString() : "null"; } @Override public String getNode1Id() { return ((LinkedDirectedGraphNode<N, E>) sourceNode).getId(); } @Override public String getNode2Id() { return ((LinkedDirectedGraphNode<N, E>) destNode).getId(); } @Override public String toString()

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS> private final CodingConvention convention; PrepareAnnotations(AbstractCompiler compiler) { this.convention = compiler.getCodingConvention(); } @Override public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) { if (n.getType() == Token.OBJECTLIT) { normalizeObjectLiteralAnnotations(n); } return true; } @Override public void visit(NodeTraversal t, Node n, Node parent) { switch (n.getType()) { case Token.CALL: annotateCalls(n); break; case Token.FUNCTION: annotateFunctions(n, parent); annotateDispatchers(n, parent); break; } } private void normalizeObjectLiteralAnnotations(Node objlit) { Preconditions.checkState(objlit.getType() == Token.OBJECTLIT); for (Node key = objlit.getFirstChild(); key != null; key = key.getNext()) { Node value = key.getFirstChild(); normalizeObjectLiteralKeyAnnotations(objlit, key, value); } } /** * There are two types of calls we are interested in calls without explicit * "this" values (what we are call "free" calls) and direct call to eval. */ private void annotateCalls(Node n) { Preconditions.checkState(n.getType() == Token.CALL); // Keep track of of the "this" context of a call. A call without an // explicit "this" is a free call. Node first = n.getFirstChild(); if (!NodeUtil.isGet(first)) { n.putBooleanProp(Node.FREE_CALL, true); } // Keep track of the context in which eval is called. It is important // to distinguish between "(0, eval)()" and "eval()". if (first.getType() == Token.NAME && "eval".equals(first.getString())) { first.putBooleanProp(Node.DIRECT_EVAL, true); } } /** * Translate dispatcher info into the property expected node. */ private void annotateDispatchers(Node n, Node parent) { Preconditions.checkState(n.getType() == Token.FUNCTION); if (parent.getJSDocInfo() != null && parent.getJSDocInfo().isJavaDispatch())

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS> { if (parent.getType() == Token.ASSIGN) { Preconditions.checkState(parent.getLastChild() == n); n.putBooleanProp(Node.IS_DISPATCHER, true); } } } /** * In the AST that Rhino gives us, it needs to make a distinction * between jsdoc on the object literal node and jsdoc on the object literal * value. For example, * <pre> * var x = { * / JSDOC / * a: 'b', * c: / JSDOC / 'd' * }; * </pre> * * But in few narrow cases (in particular, function literals), it's * a lot easier for us if the doc is attached to the value. */ private void normalizeObjectLiteralKeyAnnotations( Node objlit, Node key, Node value) { Preconditions.checkState(objlit.getType() == Token.OBJECTLIT); if (key.getJSDocInfo() != null && value.getType() == Token.FUNCTION) { value.setJSDocInfo(key.getJSDocInfo()); } } /** * Annotate optional and var_arg function parameters. */ private void annotateFunctions(Node n, Node parent) { JSDocInfo fnInfo = NodeUtil.getFunctionInfo(n); // Compute which function parameters are optional and // which are var_args. Node args = n.getFirstChild().getNext(); for (Node arg = args.getFirstChild(); arg != null; arg = arg.getNext()) { String argName = arg.getString(); JSTypeExpression typeExpr = fnInfo == null ? null : fnInfo.getParameterType(argName); if (convention.isOptionalParameter(arg) || typeExpr != null && typeExpr.isOptionalArg()) { arg.putBooleanProp(Node.IS_OPTIONAL_PARAM, true); } if (convention.isVarArgsParameter(arg) || typeExpr != null && typeExpr.isVarArgs()) { arg.putBooleanProp(Node.IS_VAR_ARGS_PARAM, true); } } } } }

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS>(NodeTraversal t, Node n, ...); // If there is a mismatch, the {@code expect} method should issue // a warning and attempt to correct the mismatch, when possible. /** * Expect the type to be an object, or a type convertible to object. If the * expectation is not met, issue a warning at the provided node's source code * position. * @return True if there was no warning, false if there was a mismatch. */ boolean expectObject(NodeTraversal t, Node n, JSType type, String msg) { if (!type.matchesObjectContext()) { mismatch(t, n, msg, type, OBJECT_TYPE); return false; } return true; } /** * Expect the type to be an object. Unlike expectObject, a type convertible * to object is not acceptable. */ void expectActualObject(NodeTraversal t, Node n, JSType type, String msg) { if (!type.isObject()) { mismatch(t, n, msg, type, OBJECT_TYPE); } } /** * Expect the type to contain an object sometimes. If the expectation is * not met, issue a warning at the provided node's source code position. */ void expectAnyObject(NodeTraversal t, Node n, JSType type, String msg) { JSType anyObjectType = getNativeType(NO_OBJECT_TYPE); if (!anyObjectType.isSubtype(type) && !type.isEmptyType()) { mismatch(t, n, msg, type, anyObjectType); } } /** * Expect the type to be a string, or a type convertible to string. If the * expectation is not met, issue a warning at the provided node's source code * position. */ void expectString(NodeTraversal t, Node n, JSType type, String msg) { if (!type.matchesStringContext()) { mismatch(t, n, msg, type, STRING_TYPE); } } /** * Expect the type to be a number, or a type convertible to number. If the * expectation is not met, issue a warning at the provided node's source code * position. */ void expectNumber(NodeTraversal t, Node n, JSType type, String msg) { if (!type.

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS>matchesNumberContext()) { mismatch(t, n, msg, type, NUMBER_TYPE); } } /** * Expect the type to be a valid operand to a bitwise operator. This includes * numbers, any type convertible to a number, or any other primitive type * (undefined|null|boolean|string). */ void expectBitwiseable(NodeTraversal t, Node n, JSType type, String msg) { if (!type.matchesNumberContext() && !type.isSubtype(allValueTypes)) { mismatch(t, n, msg, type, allValueTypes); } } /** * Expect the type to be a number or string, or a type convertible to a number * or string. If the expectation is not met, issue a warning at the provided * node's source code position. */ void expectStringOrNumber( NodeTraversal t, Node n, JSType type, String msg) { if (!type.matchesNumberContext() && !type.matchesStringContext()) { mismatch(t, n, msg, type, NUMBER_STRING); } } /** * Expect the type to be anything but the null or void type. If the * expectation is not met, issue a warning at the provided node's * source code position. Note that a union type that includes the * void type and at least one other type meets the expectation. * @return Whether the expectation was met. */ boolean expectNotNullOrUndefined( NodeTraversal t, Node n, JSType type, String msg, JSType expectedType) { if (!type.isNoType() && !type.isUnknownType() && type.isSubtype(nullOrUndefined) && !containsForwardDeclaredUnresolvedName(type)) { // There's one edge case right now that we don't handle well, and // that we don't want to warn about. // if (this.x == null) { // this.initializeX(); // this.x.foo(); // } // In this case, we incorrectly type x because of how we // infer properties locally. See issue 109. // http://code.google.com/p/closure-compiler/issues/detail?id=109 // // We do not do this inference globally.

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS> if (n.getType() == Token.GETPROP && !t.inGlobalScope() && type.isNullType()) { return true; } mismatch(t, n, msg, type, expectedType); return false; } return true; } private boolean containsForwardDeclaredUnresolvedName(JSType type) { if (type instanceof UnionType) { for (JSType alt : ((UnionType) type).getAlternates()) { if (containsForwardDeclaredUnresolvedName(alt)) { return true; } } } return type.isNoResolvedType(); } /** * Expect that the type of a switch condition matches the type of its * case condition. */ void expectSwitchMatchesCase(NodeTraversal t, Node n, JSType switchType, JSType caseType) { // ECMA-262, page 68, step 3 of evaluation of CaseBlock, // but allowing extra autoboxing. // TODO(user): remove extra conditions when type annotations // in the code base have adapted to the change in the compiler. if (!switchType.canTestForShallowEqualityWith(caseType) && (caseType.autoboxesTo() == null || !caseType.autoboxesTo().isSubtype(switchType))) { mismatch(t, n.getFirstChild(), "case expression doesn't match switch", caseType, switchType); } } /** * Expect that the first type can be addressed with GETELEM syntax, * and that the second type is the right type for an index into the * first type. * * @param t The node traversal. * @param n The node to issue warnings on. * @param objType The type of the left side of the GETELEM. * @param indexType The type inside the brackets of the GETELEM. */ void expectIndexMatch(NodeTraversal t, Node n, JSType objType, JSType indexType) { if (objType.isUnknownType()) { expectStringOrNumber(t, n, indexType, "property access"); } else if (objType.toObjectType() != null && objType.toObjectType().getIndexType() != null) { expectCanAssignTo(t, n, indexType, objType

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS> expectCanOverride(NodeTraversal t, Node n, JSType overridingType, JSType hiddenType, String propertyName, JSType ownerType) { if (!overridingType.canAssignTo(hiddenType)) { registerMismatch(overridingType, hiddenType); if (shouldReport) { compiler.report( t.makeError(n, HIDDEN_PROPERTY_MISMATCH, propertyName, ownerType.toString(), hiddenType.toString(), overridingType.toString())); } } } /** * Expect that the first type is the direct superclass of the second type. * * @param t The node traversal. * @param n The node where warnings should point to. * @param superObject The expected super instance type. * @param subObject The sub instance type. */ void expectSuperType(NodeTraversal t, Node n, ObjectType superObject, ObjectType subObject) { FunctionType subCtor = subObject.getConstructor(); ObjectType declaredSuper = subObject.getImplicitPrototype().getImplicitPrototype(); if (!declaredSuper.equals(superObject)) { if (declaredSuper.equals(getNativeType(OBJECT_TYPE))) { if (shouldReport) { compiler.report( t.makeError(n, MISSING_EXTENDS_TAG_WARNING, subObject.toString())); } registerMismatch(superObject, declaredSuper); } else { mismatch(t.getSourceName(), n, "mismatch in declaration of superclass type", superObject, declaredSuper); } // Correct the super type. if (!subCtor.hasCachedValues()) { subCtor.setPrototypeBasedOn(superObject); } } } /** * Expect that the first type can be cast to the second type. The first type * should be either a subtype or supertype of the second. * * @param t The node traversal. * @param n The node where warnings should point. * @param type The type being cast from. * @param castType The type being cast to. */ void expectCanCast(NodeTraversal t, Node n, JSType type, JSType castType) { castType = castType.restrictByNotNullOrUndefined(); type = type.restrictByNotNullOrUndefined(); if (!type.canAssignTo(

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS>castType) && !castType.canAssignTo(type)) { if (shouldReport) { compiler.report( t.makeError(n, INVALID_CAST, castType.toString(), type.toString())); } registerMismatch(type, castType); } } /** * Expect that the given variable has not been declared with a type. * * @param sourceName The name of the source file we're in. * @param n The node where warnings should point to. * @param parent The parent of {@code n}. * @param var The variable that we're checking. * @param variableName The name of the variable. * @param newType The type being applied to the variable. Mostly just here * for the benefit of the warning. */ void expectUndeclaredVariable(String sourceName, Node n, Node parent, Var var, String variableName, JSType newType) { boolean allowDupe = false; if (n.getType() == Token.GETPROP || NodeUtil.isObjectLitKey(n, parent)) { JSDocInfo info = n.getJSDocInfo(); if (info == null) { info = parent.getJSDocInfo(); } allowDupe = info != null && info.getSuppressions().contains("duplicate"); } JSType varType = var.getType(); // Only report duplicate declarations that have types. Other duplicates // will be reported by the syntactic scope creator later in the // compilation process. if (varType != null && varType != typeRegistry.getNativeType(UNKNOWN_TYPE) && newType != null && newType != typeRegistry.getNativeType(UNKNOWN_TYPE)) { // If there are two typed declarations of the same variable, that // is an error and the second declaration is ignored, except in the // case of native types. A null input type means that the declaration // was made in TypedScopeCreator#createInitialScope and is a // native type. if (var.input == null) { n.setJSType(varType); if (parent.getType() == Token.VAR) { if (n.getFirstChild() != null) { n.getFirstChild().setJSType(varType); }

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS> } else { Preconditions.checkState(parent.getType() == Token.FUNCTION); parent.setJSType(varType); } } else { // Always warn about duplicates if the overridden type does not // match the original type. // // If the types match, suppress the warning iff there was a @suppress // tag, or if the original declaration was a stub. if (!(allowDupe || var.getParentNode().getType() == Token.EXPR_RESULT) || !newType.equals(varType)) { if (shouldReport) { compiler.report( JSError.make(sourceName, n, DUP_VAR_DECLARATION, variableName, newType.toString(), var.getInputName(), String.valueOf(var.nameNode.getLineno()), varType.toString())); } } } } } /** * Expect that all properties on interfaces that this type implements are * implemented and correctly typed. */ void expectAllInterfaceProperties(NodeTraversal t, Node n, FunctionType type) { ObjectType instance = type.getInstanceType(); for (ObjectType implemented : type.getAllImplementedInterfaces()) { if (implemented.getImplicitPrototype() != null) { for (String prop : implemented.getImplicitPrototype().getOwnPropertyNames()) { expectInterfaceProperty(t, n, instance, implemented, prop); } } } } /** * Expect that the peroperty in an interface that this type implements is * implemented and correctly typed. */ private void expectInterfaceProperty(NodeTraversal t, Node n, ObjectType instance, ObjectType implementedInterface, String prop) { if (!instance.hasProperty(prop)) { // Not implemented String sourceName = (String) n.getProp(Node.SOURCENAME_PROP); sourceName = sourceName == null ? "" : sourceName; if (shouldReport) { compiler.report(JSError.make(sourceName, n, INTERFACE_METHOD_NOT_IMPLEMENTED, prop, implementedInterface.toString(), instance.toString())); } registerMismatch(instance, implementedInterface); } else { JSType found = instance.getPropertyType(prop); JSType required = implementedInterface.getImplicitPrototype().getPropertyType(prop); found = found.restrictByNotNull

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS> } registerIfMismatch(fnTypeA.getReturnType(), fnTypeB.getReturnType()); } } private void registerIfMismatch(JSType found, JSType required) { if (found != null && required != null && !found.canAssignTo(required)) { registerMismatch(found, required); } } /** * Formats a found/required error message. */ private String formatFoundRequired(String description, JSType found, JSType required) { return MessageFormat.format(FOUND_REQUIRED, description, found, required); } /** * Given a node, get a human-readable name for the type of that node so * that will be easy for the programmer to find the original declaration. * * For example, if SubFoo's property "bar" might have the human-readable * name "Foo.prototype.bar". * * @param n The node. * @param dereference If true, the type of the node will be dereferenced * to an Object type, if possible. */ String getReadableJSTypeName(Node n, boolean dereference) { // If we're analyzing a GETPROP, the property may be inherited by the // prototype chain. So climb the prototype chain and find out where // the property was originally defined. if (n.getType() == Token.GETPROP) { ObjectType objectType = getJSType(n.getFirstChild()).dereference(); if (objectType != null) { String propName = n.getLastChild().getString(); while (objectType != null && !objectType.hasOwnProperty(propName)) { objectType = objectType.getImplicitPrototype(); } // Don't show complex function names or anonymous types. // Instead, try to get a human-readable type name. if (objectType != null && (objectType.getConstructor() != null || objectType.isFunctionPrototypeType())) { return objectType.toString() + "." + propName; } } } JSType type = getJSType(n); if (dereference) { ObjectType dereferenced = type.dereference(); if (dereferenced != null) { type = dereferenced; } } String qualifiedName = n.getQualifiedName(); if (

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS>type.isFunctionPrototypeType() || (type.toObjectType() != null && type.toObjectType().getConstructor() != null)) { return type.toString(); } else if (qualifiedName != null) { return qualifiedName; } else if (type instanceof FunctionType) { // Don't show complex function names. return "function"; } else { return type.toString(); } } /** * This method gets the JSType from the Node argument and verifies that it is * present. */ private JSType getJSType(Node n) { JSType jsType = n.getJSType(); if (jsType == null) { // TODO(user): This branch indicates a compiler bug, not worthy of // halting the compilation but we should log this and analyze to track // down why it happens. This is not critical and will be resolved over // time as the type checker is extended. return getNativeType(UNKNOWN_TYPE); } else { return jsType; } } private JSType getNativeType(JSTypeNative typeId) { return typeRegistry.getNativeType(typeId); } /** * Signals that the first type and the second type have been * used interchangeably. * * Type-based optimizations should take this into account * so that they don't wreck code with type warnings. */ static class TypeMismatch { final JSType typeA; final JSType typeB; /** * It's the responsibility of the class that creates the * {@code TypeMismatch} to ensure that {@code a} and {@code b} are * non-matching types. */ TypeMismatch(JSType a, JSType b) { this.typeA = a; this.typeB = b; } @Override public boolean equals(Object object) { if (object instanceof TypeMismatch) { TypeMismatch that = (TypeMismatch) object; return (that.typeA.equals(this.typeA) && that.typeB.equals(this.typeB)) || (that.typeB.equals(this.typeA) && that.typeA.equals(this.typeB)); } return false; } @Override public int hashCode() { return Objects.

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS>() { return false; } @Override public TernaryValue testForEquality(JSType that) { TernaryValue result = super.testForEquality(that); if (result != null) { return result; } if (that.isUnknownType() || that.isSubtype( getNativeType(JSTypeNative.NUMBER_STRING_BOOLEAN)) || that.isObject()) { return UNKNOWN; } return FALSE; } @Override public boolean isBooleanValueType() { return true; } @Override public boolean matchesNumberContext() { return true; } @Override public boolean matchesStringContext() { return true; } @Override public boolean matchesObjectContext() { // TODO(user): Revisit this for ES4, which is stricter. return true; } @Override public JSType autoboxesTo() { return getNativeType(JSTypeNative.BOOLEAN_OBJECT_TYPE); } @Override public String toString() { return getDisplayName(); } @Override public String getDisplayName() { return "boolean"; } @Override public BooleanLiteralSet getPossibleToBooleanOutcomes() { return BooleanLiteralSet.BOTH; } @Override public <T> T visit(Visitor<T> visitor) { return visitor.caseBooleanType(); } }

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS>namespace == null) { namespace = new GlobalNamespace(compiler, root); } overrideDefines(collectDefines(root, namespace)); } private void overrideDefines(Map<String, DefineInfo> allDefines) { boolean changed = false; for (Map.Entry<String, DefineInfo> def : allDefines.entrySet()) { String defineName = def.getKey(); DefineInfo info = def.getValue(); Node inputValue = dominantReplacements.get(defineName); Node finalValue = inputValue != null ? inputValue : info.getLastValue(); if (finalValue != info.initialValue) { info.initialValueParent.replaceChild( info.initialValue, finalValue.cloneTree()); compiler.addToDebugLog("Overriding @define variable " + defineName); changed = changed || finalValue.getType() != info.initialValue.getType() || !finalValue.isEquivalentTo(info.initialValue); } } if (changed) { compiler.reportCodeChange(); } Set<String> unusedReplacements = dominantReplacements.keySet(); unusedReplacements.removeAll(allDefines.keySet()); unusedReplacements.removeAll(KNOWN_DEFINES); for (String unknownDefine : unusedReplacements) { compiler.report(JSError.make(UNKNOWN_DEFINE_WARNING, unknownDefine)); } } private static String format(MessageFormat format, Object... params) { return format.format(params); } /** * Only defines of literal number, string, or boolean are supported. */ private boolean isValidDefineType(JSTypeExpression expression) { JSType type = expression.evaluate(null, compiler.getTypeRegistry()); return !type.isUnknownType() && type.isSubtype( compiler.getTypeRegistry().getNativeType( JSTypeNative.NUMBER_STRING_BOOLEAN)); } /** * Finds all defines, and creates a {@link DefineInfo} data structure for * each one. * @return A map of {@link DefineInfo} structures, keyed by name. */ private Map<String, DefineInfo> collectDefines(Node root, GlobalNamespace namespace) { // Find all the global names with a @define annotation List<Name> allDefines = Lists.newArrayList(); for (Name name : namespace.getName

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS>Deque<Integer>(); assignAllowed.push(1); // Create a map of references to defines keyed by node for easy lookup allRefInfo = Maps.newHashMap(); for (Name name : listOfDefines) { if (name.declaration != null) { allRefInfo.put(name.declaration.node, new RefInfo(name.declaration, name)); } if (name.refs != null) { for (Ref ref : name.refs) { // If there's a TWIN def, only put one of the twins in. if (ref.getTwin() == null || !ref.getTwin().isSet()) { allRefInfo.put(ref.node, new RefInfo(ref, name)); } } } } } /** * Get a map of {@link DefineInfo} structures, keyed by the name of * the define. */ Map<String, DefineInfo> getAllDefines() { return allDefines; } /** * Keeps track of whether the traversal is in a conditional branch. * We traverse all nodes of the parse tree. */ public boolean shouldTraverse(NodeTraversal nodeTraversal, Node n, Node parent) { updateAssignAllowedStack(n, true); return true; } public void visit(NodeTraversal t, Node n, Node parent) { RefInfo refInfo = allRefInfo.get(n); if (refInfo != null) { Ref ref = refInfo.ref; Name name = refInfo.name; String fullName = name.fullName(); switch (ref.type) { case SET_FROM_GLOBAL: case SET_FROM_LOCAL: Node valParent = getValueParent(ref); Node val = valParent.getLastChild(); if (valParent.getType() == Token.ASSIGN && name.isSimpleName() && name.declaration == ref) { // For defines, it's an error if a simple name is assigned // before it's declared compiler.report( t.makeError(val, INVALID_DEFINE_INIT_ERROR, fullName)); } else if (processDefineAssignment(t, fullName, val, valParent)) { // remove the assignment so that the variable is still declared, // but no longer assigned to a value, e.g

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS> setDefineInfoNotAssignable(info, t); } assignableDefines.clear(); } } updateAssignAllowedStack(n, false); } /** * Determines whether assignment to a define should be allowed * in the subtree of the given node, and if not, records that fact. * * @param n The node whose subtree we're about to enter or exit. * @param entering True if we're entering the subtree, false otherwise. */ private void updateAssignAllowedStack(Node n, boolean entering) { switch (n.getType()) { case Token.CASE: case Token.FOR: case Token.FUNCTION: case Token.HOOK: case Token.IF: case Token.SWITCH: case Token.WHILE: if (entering) { assignAllowed.push(0); } else { assignAllowed.remove(); } break; } } /** * Determines whether assignment to a define should be allowed * at the current point of the traversal. */ private boolean isAssignAllowed() { return assignAllowed.element() == 1; } /** * Tracks the given define. * * @param t The current traversal, for context. * @param name The full name for this define. * @param value The value assigned to the define. * @param valueParent The parent node of value. * @return Whether we should remove this assignment from the parse tree. */ private boolean processDefineAssignment(NodeTraversal t, String name, Node value, Node valueParent) { if (value == null || !NodeUtil.isValidDefineValue(value, allDefines.keySet())) { compiler.report( t.makeError(value, INVALID_DEFINE_INIT_ERROR, name)); } else if (!isAssignAllowed()) { compiler.report( t.makeError(valueParent, NON_GLOBAL_DEFINE_INIT_ERROR, name)); } else { DefineInfo info = allDefines.get(name); if (info == null) { // First declaration of this define. info = new DefineInfo(value, valueParent); allDefines.put(name, info); assignableDefines.put(name, info); } else if (info.recordAssignment(value)) { // The define

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS>; } /** * Records the fact that this define can't be assigned a value anymore. * * @param reason A message describing the reason why it can't be assigned. */ public void setNotAssignable(String reason) { isAssignable = false; reasonNotAssignable = reason; } /** * Gets the reason why a define is not assignable. */ public String getReasonWhyNotAssignable() { return reasonNotAssignable; } /** * Records an assigned value. * * @return False if there was an error. */ public boolean recordAssignment(Node value) { lastValue = value; return isAssignable; } /** * Gets the last assigned value. */ public Node getLastValue() { return lastValue; } } }

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS>.checkNotNull(parent); if (refinedScope != null && getScope() != refinedScope) { curNode = node; pushScope(refinedScope); traverseBranch(node, parent); popScope(); } else { traverseBranch(node, parent); } } /** * Gets the compiler. */ public Compiler getCompiler() { // TODO(nicksantos): Remove this type cast. This is just temporary // while refactoring. return (Compiler) compiler; } /** * Gets the current line number, or zero if it cannot be determined. The line * number is retrieved lazily as a running time optimization. */ public int getLineNumber() { Node cur = curNode; while (cur != null) { int line = cur.getLineno(); if (line >=0) { return line; } cur = cur.getParent(); } return 0; } /** * Gets the current input source name. * * @return A string that may be empty, but not null */ public String getSourceName() { return sourceName; } /** * Gets the current input source. */ public CompilerInput getInput() { return compiler.getInput(sourceName); } /** * Gets the current input module. */ public JSModule getModule() { CompilerInput input = getInput(); return input == null ? null : input.getModule(); } /** Returns the node currently being traversed. */ public Node getCurrentNode() { return curNode; } /** * Traverses a node recursively. */ public static void traverse( AbstractCompiler compiler, Node root, Callback cb) { NodeTraversal t = new NodeTraversal(compiler, cb); t.traverse(root); } /** * Traverses a list of node trees. */ public static void traverseRoots( AbstractCompiler compiler, List<Node> roots, Callback cb) { NodeTraversal t = new NodeTraversal(compiler, cb); t.traverseRoots(roots); } /** * Traverses a branch. */ @SuppressWarnings("fallthrough") private void traverseBranch(Node n, Node parent) { int type = n.getType(); if (type == Token

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS>.SCRIPT) { sourceName = getSourceName(n); } curNode = n; if (!callback.shouldTraverse(this, n, parent)) return; switch (type) { case Token.FUNCTION: traverseFunction(n, parent); break; default: for (Node child = n.getFirstChild(); child != null; ) { // child could be replaced, in which case our child node // would no longer point to the true next Node next = child.getNext(); traverseBranch(child, n); child = next; } break; } curNode = n; callback.visit(this, n, parent); } /** * Traverses a function. */ private void traverseFunction(Node n, Node parent) { Preconditions.checkState(n.getChildCount() == 3); Preconditions.checkState(n.getType() == Token.FUNCTION); final Node fnName = n.getFirstChild(); boolean isFunctionExpression = (parent != null) && NodeUtil.isFunctionExpression(n); if (!isFunctionExpression) { // Functions declarations are in the scope containing the declaration. traverseBranch(fnName, n); } curNode = n; pushScope(n); if (isFunctionExpression) { // Function expression names are only accessible within the function // scope. traverseBranch(fnName, n); } final Node args = fnName.getNext(); final Node body = args.getNext(); // Args traverseBranch(args, n); // Body Preconditions.checkState(body.getNext() == null && body.getType() == Token.BLOCK); traverseBranch(body, n); popScope(); } /** Examines the functions stack for the last instance of a function node. */ @SuppressWarnings("unchecked") public Node getEnclosingFunction() { if (scopes.size() + scopeRoots.size() < 2) { return null; } else { if (scopeRoots.isEmpty()) { return scopes.peek().getRootNode(); } else { return scopeRoots.peek(); } } } /** Creates a new scope (e.g. when entering a function). */ private void pushScope(Node node) { Preconditions.checkState(curNode !=

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS> return !(scopes.isEmpty() && scopeRoots.isEmpty()); } /** Reports a diagnostic (error or warning) */ public void report(Node n, DiagnosticType diagnosticType, String... arguments) { JSError error = JSError.make(getSourceName(), n, diagnosticType, arguments); compiler.report(error); } private static String getSourceName(Node n) { String name = (String) n.getProp(Node.SOURCENAME_PROP); return name == null ? "" : name; } /** * Creates a JSError during NodeTraversal. * * @param n Determines the line and char position within the source file name * @param type The DiagnosticType * @param arguments Arguments to be incorporated into the message */ public JSError makeError(Node n, CheckLevel level, DiagnosticType type, String... arguments) { return JSError.make(getSourceName(), n, level, type, arguments); } /** * Creates a JSError during NodeTraversal. * * @param n Determines the line and char position within the source file name * @param type The DiagnosticType * @param arguments Arguments to be incorporated into the message */ public JSError makeError(Node n, DiagnosticType type, String... arguments) { return JSError.make(getSourceName(), n, type, arguments); } }

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS> // Output printInputDelimiter = false; prettyPrint = false; lineBreak = false; reportPath = null; tracer = TracerMode.OFF; colorizeErrorOutput = false; errorFormat = ErrorFormat.SINGLELINE; warningsGuard = null; debugFunctionSideEffectsPath = null; jsOutputFile = ""; externExports = false; nameReferenceReportPath = null; nameReferenceGraphPath = null; // Debugging aliasHandler = NULL_ALIAS_TRANSFORMATION_HANDLER; operaCompoundAssignFix = true; } /** * Returns the map of define replacements. */ public Map<String, Node> getDefineReplacements() { return getReplacementsHelper(defineReplacements); } /** * Returns the map of tweak replacements. */ public Map<String, Node> getTweakReplacements() { return getReplacementsHelper(tweakReplacements); } /** * Creates a map of String->Node from a map of String->Number/String/Boolean. */ private static Map<String, Node> getReplacementsHelper( Map<String, Object> source) { Map<String, Node> map = Maps.newHashMap(); for (Map.Entry<String, Object> entry : source.entrySet()) { String name = entry.getKey(); Object value = entry.getValue(); if (value instanceof Boolean) { map.put(name, ((Boolean) value).booleanValue() ? new Node(Token.TRUE) : new Node(Token.FALSE)); } else if (value instanceof Integer) { map.put(name, Node.newNumber(((Integer) value).intValue())); } else if (value instanceof Double) { map.put(name, Node.newNumber(((Double) value).doubleValue())); } else { Preconditions.checkState(value instanceof String); map.put(name, Node.newString((String) value)); } } return map; } /** * Sets the value of the {@code @define} variable in JS * to a boolean literal. */ public void setDefineToBooleanLiteral(String defineName, boolean value) { defineReplacements.put(defineName, new Boolean(value)); } /** * Sets the value of the {@code @define

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS>} variable in JS to a * String literal. */ public void setDefineToStringLiteral(String defineName, String value) { defineReplacements.put(defineName, value); } /** * Sets the value of the {@code @define} variable in JS to a * number literal. */ public void setDefineToNumberLiteral(String defineName, int value) { defineReplacements.put(defineName, new Integer(value)); } /** * Sets the value of the {@code @define} variable in JS to a * number literal. */ public void setDefineToDoubleLiteral(String defineName, double value) { defineReplacements.put(defineName, new Double(value)); } /** * Sets the value of the tweak in JS * to a boolean literal. */ public void setTweakToBooleanLiteral(String tweakId, boolean value) { tweakReplacements.put(tweakId, new Boolean(value)); } /** * Sets the value of the tweak in JS to a * String literal. */ public void setTweakToStringLiteral(String tweakId, String value) { tweakReplacements.put(tweakId, value); } /** * Sets the value of the tweak in JS to a * number literal. */ public void setTweakToNumberLiteral(String tweakId, int value) { tweakReplacements.put(tweakId, new Integer(value)); } /** * Sets the value of the tweak in JS to a * number literal. */ public void setTweakToDoubleLiteral(String tweakId, double value) { tweakReplacements.put(tweakId, new Double(value)); } /** * Skip all possible passes, to make the compiler as fast as possible. */ public void skipAllCompilerPasses() { skipAllPasses = true; } /** * Whether the warnings guard in this Options object enables the given * group of warnings. */ boolean enables(DiagnosticGroup type) { return warningsGuard != null && warningsGuard.enables(type); } /** * Whether the warnings guard in this Options object disables the given * group of warnings. */ boolean disables(DiagnosticGroup type) { return warningsGuard != null && warningsGuard.disable

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS>s(type); } /** * Configure the given type of warning to the given level. */ public void setWarningLevel(DiagnosticGroup type, CheckLevel level) { addWarningsGuard(new DiagnosticGroupWarningsGuard(type, level)); } WarningsGuard getWarningsGuard() { return warningsGuard; } /** * Add a guard to the set of warnings guards. */ public void addWarningsGuard(WarningsGuard guard) { if (warningsGuard == null) { warningsGuard = new ComposeWarningsGuard(guard); } else { warningsGuard.addGuard(guard); } } /** * Sets the variable and property renaming policies for the compiler, * in a way that clears warnings about the renaming policy being * uninitialized from flags. */ public void setRenamingPolicy(VariableRenamingPolicy newVariablePolicy, PropertyRenamingPolicy newPropertyPolicy) { this.variableRenaming = newVariablePolicy; this.propertyRenaming = newPropertyPolicy; } public void setPropertyAffinity(boolean useAffinity) { this.propertyAffinity = useAffinity; } /** Should shadow outer scope variable name during renaming. */ public void setShadowVariables(boolean shadow) { this.shadowVariables = shadow; } /** * If true, flattens multi-level property names on extern types * (e.g. String$f = x). This should only be used with the typed version of * the externs files. */ public void setCollapsePropertiesOnExternTypes(boolean collapse) { collapsePropertiesOnExternTypes = collapse; } /** * If true, process goog.testing.ObjectPropertyString instances. */ public void setProcessObjectPropertyString(boolean process) { processObjectPropertyString = process; } /** * Sets the id generators to replace. */ public void setIdGenerators(Set<String> idGenerators) { this.idGenerators = Sets.newHashSet(idGenerators); } /** * Sets the functions whose debug strings to replace. */ public void setReplaceStringsConfiguration( String placeholderToken, List<String> functionDescriptors) { this.replaceStringsPlaceholderToken = placeholderToken; this.replaceStringsFunctionDescriptions = Lists.newArrayList(functionDescriptors); } public void setRewriteNewDateG

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS>oogNow(boolean rewrite) { this.rewriteNewDateGoogNow = rewrite; } public void setRemoveAbstractMethods(boolean remove) { this.removeAbstractMethods = remove; } public void setRemoveClosureAsserts(boolean remove) { this.removeClosureAsserts = remove; } /** * If true, name anonymous functions only. All other passes will be skipped. */ public void setNameAnonymousFunctionsOnly(boolean value) { this.nameAnonymousFunctionsOnly = value; } public void lineLengthThreshold(int value) { this.lineLengthThreshold = value; } public void setColorizeErrorOutput(boolean colorizeErrorOutput) { this.colorizeErrorOutput = colorizeErrorOutput; } public boolean shouldColorizeErrorOutput() { return colorizeErrorOutput; } /** * If true, chain calls to functions that return this. */ public void setChainCalls(boolean value) { this.chainCalls = value; } /** * If true, accept `const' keyword. */ public void setAcceptConstKeyword(boolean value) { this.acceptConstKeyword = value; } /** * Enable runtime type checking, which adds JS type assertions for debugging. * * @param logFunction A JS function to be used for logging runtime type * assertion failures. */ public void enableRuntimeTypeCheck(String logFunction) { this.runtimeTypeCheck = true; this.runtimeTypeCheckLogFunction = logFunction; } public void disableRuntimeTypeCheck() { this.runtimeTypeCheck = false; } public void setGenerateExports(boolean generateExports) { this.generateExports = generateExports; } public void setCodingConvention(CodingConvention codingConvention) { this.codingConvention = codingConvention; } public CodingConvention getCodingConvention() { return codingConvention; } /** * Sort inputs by their goog.provide/goog.require calls, and prune inputs * whose symbols are not required. */ public void setManageClosureDependencies(boolean newVal) { manageClosureDependencies = newVal; } /** * Sort inputs by their goog.provide/goog.require calls. * * @param entryPoints Entry points to the program. Must be goog.provide'd

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS>/* * * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is Rhino code, released * May 6, 1999. * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1997-1999 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Bob Jervis * Google Inc. * * Alternatively, the contents of this file may be used under the terms of * the GNU General Public License Version 2 or later (the "GPL"), in which * case the provisions of the GPL are applicable instead of those above. If * you wish to allow use of your version of this file only under the terms of * the GPL and not to allow others to use your version of this file under the * MPL, indicate your decision by deleting the provisions above and replacing * them with the notice and other provisions required by the GPL. If you do * not delete the provisions above, a recipient may use your version of this * file under either the MPL or the GPL. * * ***** END LICENSE BLOCK ***** */ package com.google.javascript.rhino.jstype; import static com.google.javascript.rhino.jstype.TernaryValue.FALSE; import static com.google.javascript.rhino.jstype.TernaryValue.UNKNOWN; /** * String type. */ public final class StringType extends ValueType { private static final long serialVersionUID = 1L; StringType(JSTypeRegistry registry) { super(registry); } @Override public Ternary

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS>Value testForEquality(JSType that) { TernaryValue result = super.testForEquality(that); if (result != null) { return result; } if (that.isUnknownType() || that.isSubtype( getNativeType(JSTypeNative.OBJECT_NUMBER_STRING_BOOLEAN))) { return UNKNOWN; } return FALSE; } @Override public boolean isStringValueType() { return true; } @Override public boolean matchesNumberContext() { return true; } @Override public boolean matchesStringContext() { return true; } @Override public boolean matchesObjectContext() { // TODO(user): Revisit this for ES4, which is stricter. return true; } @Override public String toString() { return getDisplayName(); } @Override public String getDisplayName() { return "string"; } @Override public JSType autoboxesTo() { return getNativeType(JSTypeNative.STRING_OBJECT_TYPE); } @Override public BooleanLiteralSet getPossibleToBooleanOutcomes() { return BooleanLiteralSet.BOTH; } @Override public <T> T visit(Visitor<T> visitor) { return visitor.caseStringType(); } }

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS> The order that the guards are applied in. private final TreeSet<WarningsGuard> guards = new TreeSet<WarningsGuard>(guardComparator); public ComposeWarningsGuard(List<WarningsGuard> guards) { addGuards(guards); } public ComposeWarningsGuard(WarningsGuard... guards) { this(Lists.newArrayList(guards)); } void addGuard(WarningsGuard guard) { if (guard instanceof ComposeWarningsGuard) { // Reverse the guards, so that they have the same order in the result. addGuards(((ComposeWarningsGuard) guard).guards.descendingSet()); } else { numberOfAdds++; orderOfAddition.put(guard, numberOfAdds); guards.remove(guard); guards.add(guard); } } private void addGuards(Iterable<WarningsGuard> guards) { for (WarningsGuard guard : guards) { addGuard(guard); } } @Override public CheckLevel level(JSError error) { for (WarningsGuard guard : guards) { CheckLevel newLevel = guard.level(error); if (newLevel != null) { return newLevel; } } return null; } @Override public boolean disables(DiagnosticGroup group) { nextSingleton: for (DiagnosticType type : group.getTypes()) { DiagnosticGroup singleton = DiagnosticGroup.forType(type); for (WarningsGuard guard : guards) { if (guard.disables(singleton)) { continue nextSingleton; } else if (guard.enables(singleton)) { return false; } } return false; } return true; } /** * Determines whether this guard will "elevate" the status of any disabled * diagnostic type in the group to a warning or an error. */ @Override public boolean enables(DiagnosticGroup group) { for (WarningsGuard guard : guards) { if (guard.enables(group)) { return true; } else if (guard.disables(group)) { return false; } } return false; } List<WarningsGuard> getGuards() { return Collections.unmodifiableList(Lists.newArrayList(guards)); } @Override public String

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS> } /** * Generates a list of modules from a list of inputs, such that modules * form a bush formation. In a bush formation, module 2 depends * on module 1, and all other modules depend on module 2. */ static JSModule[] createModuleBush(String ... inputs) { Preconditions.checkState(inputs.length > 2); JSModule[] modules = createModules(inputs); for (int i = 1; i < modules.length; i++) { modules[i].addDependency(modules[i == 1 ? 0 : 1]); } return modules; } /** * Generates a list of modules from a list of inputs, such that modules * form a tree formation. In a tree formation, module N depends on * module `floor(N/2)`, So the modules form a balanced binary tree. */ static JSModule[] createModuleTree(String ... inputs) { JSModule[] modules = createModules(inputs); for (int i = 1; i < modules.length; i++) { modules[i].addDependency(modules[(i - 1) / 2]); } return modules; } /** * Generates a list of modules from a list of inputs. Does not generate any * dependencies between the modules. */ static JSModule[] createModules(String... inputs) { JSModule[] modules = new JSModule[inputs.length]; for (int i = 0; i < inputs.length; i++) { JSModule module = modules[i] = new JSModule("m" + i); module.add(JSSourceFile.fromCode("i" + i, inputs[i])); } return modules; } private static class BlackHoleErrorManager extends BasicErrorManager { private BlackHoleErrorManager(Compiler compiler) { compiler.setErrorManager(this); } @Override public void println(CheckLevel level, JSError error) {} @Override public void printSummary() {} } Compiler createCompiler() { Compiler compiler = new Compiler(); return compiler; } protected void setExpectedSymbolTableError(DiagnosticType type) { this.expectedSymbolTableError = type; } /** Finds the first matching qualified name node in post-traversal order.

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS> unknown types in JSTypeNative. private final boolean isChecked; UnknownType(JSTypeRegistry registry, boolean isChecked) { super(registry); this.isChecked = isChecked; } @Override public boolean isUnknownType() { return true; } @Override public boolean isCheckedUnknownType() { return isChecked; } @Override public boolean canAssignTo(JSType that) { return true; } @Override public boolean canBeCalled() { return true; } @Override public boolean matchesNumberContext() { return true; } @Override public boolean matchesObjectContext() { return true; } @Override public boolean matchesStringContext() { return true; } @Override public TernaryValue testForEquality(JSType that) { return UNKNOWN; } @Override public boolean isNullable() { return true; } @Override public boolean isSubtype(JSType that) { return true; } @Override public <T> T visit(Visitor<T> visitor) { return visitor.caseUnknownType(); } @Override public String toString() { return getReferenceName(); } @Override boolean defineProperty(String propertyName, JSType type, boolean inferred, boolean inExterns, Node propertyNode) { // nothing to define return true; } @Override public ObjectType getImplicitPrototype() { return null; } @Override public int getPropertiesCount() { return Integer.MAX_VALUE; } @Override void collectPropertyNames(Set<String> props) { } @Override public JSType getPropertyType(String propertyName) { return this; } @Override public boolean hasProperty(String propertyName) { return true; } @Override public FunctionType getConstructor() { return null; } @Override public String getReferenceName() { return isChecked ? "??" : "?"; } @Override public String getDisplayName() { return "Unknown"; } @Override public boolean hasDisplayName() { return true; } @Override public boolean isPropertyTypeDeclared(String propertyName) { return false; } @Override public boolean isPropertyTypeInferred(

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS> serialVersionUID = 1L; VoidType(JSTypeRegistry registry) { super(registry); } @Override public JSType restrictByNotNullOrUndefined() { return registry.getNativeType(JSTypeNative.NO_TYPE); } @Override public TernaryValue testForEquality(JSType that) { if (UNKNOWN.equals(super.testForEquality(that))) { return UNKNOWN; } if (that.isSubtype(this) || that.isSubtype(getNativeType(JSTypeNative.NULL_TYPE))) { return TRUE; } return FALSE; } @Override public boolean matchesNumberContext() { return false; } @Override public boolean matchesObjectContext() { return false; } @Override public boolean matchesStringContext() { return true; } @Override public boolean isVoidType() { return true; } @Override public String toString() { return getDisplayName(); } @Override public String getDisplayName() { return "undefined"; } @Override public BooleanLiteralSet getPossibleToBooleanOutcomes() { return BooleanLiteralSet.FALSE; } @Override public <T> T visit(Visitor<T> visitor) { return visitor.caseVoidType(); } }

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS> link. * If there is no next link, returns the blind scope. */ protected FlowScope nextPreciserScopeKnowingConditionOutcome(Node condition, FlowScope blindScope, boolean outcome) { return nextLink != null ? nextLink.getPreciserScopeKnowingConditionOutcome( condition, blindScope, outcome) : blindScope; } /** * Returns the type of a node in the given scope if the node corresponds to a * name whose type is capable of being refined. * @return The current type of the node if it can be refined, null otherwise. */ JSType getTypeIfRefinable(Node node, FlowScope scope) { switch (node.getType()) { case Token.NAME: StaticSlot<JSType> nameVar = scope.getSlot(node.getString()); if (nameVar != null) { JSType nameVarType = nameVar.getType(); if (nameVarType == null) { nameVarType = node.getJSType(); } return nameVarType; } return null; case Token.GETPROP: String qualifiedName = node.getQualifiedName(); if (qualifiedName == null) { return null; } StaticSlot<JSType> propVar = scope.getSlot(qualifiedName); JSType propVarType = null; if (propVar != null) { propVarType = propVar.getType(); } if (propVarType == null) { propVarType = node.getJSType(); } if (propVarType == null) { propVarType = getNativeType(UNKNOWN_TYPE); } return propVarType; } return null; } /** * Declares a refined type in {@code scope} for the name represented by * {@code node}. It must be possible to refine the type of the given node in * the given scope, as determined by {@link #getTypeIfRefinable}. */ protected void declareNameInScope(FlowScope scope, Node node, JSType type) { switch (node.getType()) { case Token.NAME: scope.inferSlotType(node.getString(), type); break; case Token.GETPROP: String qualifiedName = node.getQualifiedName(); Preconditions.checkNotNull

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS>(qualifiedName); JSType origType = node.getJSType(); origType = origType == null ? getNativeType(UNKNOWN_TYPE) : origType; scope.inferQualifiedSlot(qualifiedName, origType, type); break; default: throw new IllegalArgumentException("Node cannot be refined. \n" + node.toStringTree()); } } /** * @see #getRestrictedWithoutUndefined(JSType) */ private final Visitor<JSType> restrictUndefinedVisitor = new Visitor<JSType>() { public JSType caseEnumElementType(EnumElementType enumElementType) { JSType type = enumElementType.getPrimitiveType().visit(this); if (type != null && enumElementType.getPrimitiveType().equals(type)) { return enumElementType; } else { return type; } } public JSType caseAllType() { return typeRegistry.createUnionType(OBJECT_TYPE, NUMBER_TYPE, STRING_TYPE, BOOLEAN_TYPE, NULL_TYPE); } public JSType caseNoObjectType() { return getNativeType(NO_OBJECT_TYPE); } public JSType caseNoType() { return getNativeType(NO_TYPE); } public JSType caseBooleanType() { return getNativeType(BOOLEAN_TYPE); } public JSType caseFunctionType(FunctionType type) { return type; } public JSType caseNullType() { return getNativeType(NULL_TYPE); } public JSType caseNumberType() { return getNativeType(NUMBER_TYPE); } public JSType caseObjectType(ObjectType type) { return type; } public JSType caseStringType() { return getNativeType(STRING_TYPE); } public JSType caseUnionType(UnionType type) { return type.getRestrictedUnion(getNativeType(VOID_TYPE)); } public JSType caseUnknownType() { return getNativeType(UNKNOWN_TYPE); } public JSType caseVoidType() { return null; } }; /** * @see #getRestrictedWithoutNull(JSType) */ private final Visitor<JSType> restrictNullVisitor = new Visitor<JSType>() { public JSType caseEnumElementType(EnumElementType enumElementType) { JSType type =

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS> enumElementType.getPrimitiveType().visit(this); if (type != null && enumElementType.getPrimitiveType().equals(type)) { return enumElementType; } else { return type; } } public JSType caseAllType() { return typeRegistry.createUnionType(OBJECT_TYPE, NUMBER_TYPE, STRING_TYPE, BOOLEAN_TYPE, VOID_TYPE); } public JSType caseNoObjectType() { return getNativeType(NO_OBJECT_TYPE); } public JSType caseNoType() { return getNativeType(NO_TYPE); } public JSType caseBooleanType() { return getNativeType(BOOLEAN_TYPE); } public JSType caseFunctionType(FunctionType type) { return type; } public JSType caseNullType() { return null; } public JSType caseNumberType() { return getNativeType(NUMBER_TYPE); } public JSType caseObjectType(ObjectType type) { return type; } public JSType caseStringType() { return getNativeType(STRING_TYPE); } public JSType caseUnionType(UnionType type) { return type.getRestrictedUnion(getNativeType(NULL_TYPE)); } public JSType caseUnknownType() { return getNativeType(UNKNOWN_TYPE); } public JSType caseVoidType() { return getNativeType(VOID_TYPE); } }; /** * A class common to all visitors that need to restrict the type based on * {@code typeof}-like conditions. */ abstract class RestrictByTypeOfResultVisitor implements Visitor<JSType> { /** * Abstracts away the similarities between visiting the unknown type and the * all type. * @param topType {@code UNKNOWN_TYPE} or {@code ALL_TYPE} * @return the restricted type * @see #caseAllType * @see #caseUnknownType */ protected abstract JSType caseTopType(JSType topType); public JSType caseAllType() { return caseTopType(getNativeType(ALL_TYPE)); } public JSType caseUnknownType() { return caseTopType(getNativeType(UNKNOWN_TYPE)); } public JSType caseUnionType(UnionType type) { JSType restricted

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS> = null; for (JSType alternate : type.getAlternates()) { JSType restrictedAlternate = alternate.visit(this); if (restrictedAlternate != null) { if (restricted == null) { restricted = restrictedAlternate; } else { restricted = restrictedAlternate.getLeastSupertype(restricted); } } } return restricted; } public JSType caseNoType() { return getNativeType(NO_TYPE); } public JSType caseEnumElementType(EnumElementType enumElementType) { // NOTE(nicksantos): This is a white lie. Suppose we have: // /** @enum {string|number} */ var MyEnum = ...; // if (goog.isNumber(myEnumInstance)) { // /* what is myEnumInstance here? */ // } // There is no type that represents {MyEnum - string}. What we really // need is a notion of "enum subtyping", so that we could dynamically // create a subtype of MyEnum restricted by string. In any case, // this should catch the common case. JSType type = enumElementType.getPrimitiveType().visit(this); if (type != null && enumElementType.getPrimitiveType().equals(type)) { return enumElementType; } else { return type; } } } /** * A class common to all visitors that need to restrict the type based on * some {@code typeof}-like condition being true. All base cases return * {@code null}. It is up to the subclasses to override the appropriate ones. */ abstract class RestrictByTrueTypeOfResultVisitor extends RestrictByTypeOfResultVisitor { public JSType caseNoObjectType() { return null; } public JSType caseBooleanType() { return null; } public JSType caseFunctionType(FunctionType type) { return null; } public JSType caseNullType() { return null; } public JSType caseNumberType() { return null; } public JSType caseObjectType(ObjectType type) { return null; } public JSType caseStringType() { return null; } public JSType caseVoidType() { return null; } } /** * A class common to all visitors that need to restrict the type based on

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS> * some {@code typeof}-like condition being false. All base cases return * their type. It is up to the subclasses to override the appropriate ones. */ abstract class RestrictByFalseTypeOfResultVisitor extends RestrictByTypeOfResultVisitor { @Override protected JSType caseTopType(JSType topType) { return topType; } public JSType caseNoObjectType() { return getNativeType(NO_OBJECT_TYPE); } public JSType caseBooleanType() { return getNativeType(BOOLEAN_TYPE); } public JSType caseFunctionType(FunctionType type) { return type; } public JSType caseNullType() { return getNativeType(NULL_TYPE); } public JSType caseNumberType() { return getNativeType(NUMBER_TYPE); } public JSType caseObjectType(ObjectType type) { return type; } public JSType caseStringType() { return getNativeType(STRING_TYPE); } public JSType caseVoidType() { return getNativeType(VOID_TYPE); } } /** * @see ChainableReverseAbstractInterpreter#getRestrictedByTypeOfResult */ private class RestrictByOneTypeOfResultVisitor extends RestrictByTypeOfResultVisitor { /** * A value known to be equal or not equal to the result of the * {@code typeOf} operation. */ private final String value; /** * {@code true} if the {@code typeOf} result is known to equal * {@code value}; {@code false} if it is known <em>not</em> to equal * {@code value}. */ private final boolean resultEqualsValue; RestrictByOneTypeOfResultVisitor(String value, boolean resultEqualsValue) { this.value = value; this.resultEqualsValue = resultEqualsValue; } /** * Computes whether the given result of a {@code typeof} operator matches * expectations, i.e. whether a type that gives such a result should be * kept. */ private boolean matchesExpectation(String result) { return result.equals(value) == resultEqualsValue; } @Override protected JSType caseTopType(JSType topType) { JSType result = topType; if (resultEqualsValue) { JSType typeByName

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS> = getNativeTypeForTypeOf(value); if (typeByName != null) { result = typeByName; } } return result; } public JSType caseNoObjectType() { return (value.equals("object") || value.equals("function")) == resultEqualsValue ? getNativeType(NO_OBJECT_TYPE) : null; } public JSType caseBooleanType() { return matchesExpectation("boolean") ? getNativeType(BOOLEAN_TYPE) : null; } public JSType caseFunctionType(FunctionType type) { return matchesExpectation("function") ? type : null; } public JSType caseNullType() { return matchesExpectation("object") ? getNativeType(NULL_TYPE) : null; } public JSType caseNumberType() { return matchesExpectation("number") ? getNativeType(NUMBER_TYPE) : null; } public JSType caseObjectType(ObjectType type) { if (value.equals("function")) { JSType ctorType = getNativeType(U2U_CONSTRUCTOR_TYPE); return resultEqualsValue && ctorType.isSubtype(type) ? ctorType : null; } return matchesExpectation("object") ? type : null; } public JSType caseStringType() { return matchesExpectation("string") ? getNativeType(STRING_TYPE) : null; } public JSType caseVoidType() { return matchesExpectation("undefined") ? getNativeType(VOID_TYPE) : null; } } /** * Returns a version of type where undefined is not present. */ final JSType getRestrictedWithoutUndefined(JSType type) { return type == null ? null : type.visit(restrictUndefinedVisitor); } /** * Returns a version of type where null is not present. */ final JSType getRestrictedWithoutNull(JSType type) { return type == null ? null : type.visit(restrictNullVisitor); } /** * Returns a version of {@code type} that is restricted by some knowledge * about the result of the {@code typeof} operation. * <p> * The behavior of the {@code typeof} operator can be summarized by the * following table: * <table> * <tr><th>type</th><th>result</th></tr>

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS> * <tr><td>{@code undefined}</td><td>"undefined"</td></tr> * <tr><td>{@code null}</td><td>"object"</td></tr> * <tr><td>{@code boolean}</td><td>"boolean"</td></tr> * <tr><td>{@code number}</td><td>"number"</td></tr> * <tr><td>{@code string}</td><td>"string"</td></tr> * <tr><td>{@code Object} (which doesn't implement [[Call]])</td> * <td>"object"</td></tr> * <tr><td>{@code Object} (which implements [[Call]])</td> * <td>"function"</td></tr> * </table> * @param type the type to restrict * @param value A value known to be equal or not equal to the result of the * {@code typeof} operation * @param resultEqualsValue {@code true} if the {@code typeOf} result is known * to equal {@code value}; {@code false} if it is known <em>not</em> to * equal {@code value} * @return the restricted type or null if no version of the type matches the * restriction */ JSType getRestrictedByTypeOfResult(JSType type, String value, boolean resultEqualsValue) { if (type == null) { if (resultEqualsValue) { JSType result = getNativeTypeForTypeOf(value); return result == null ? getNativeType(UNKNOWN_TYPE) : result; } else { return null; } } return type.visit( new RestrictByOneTypeOfResultVisitor(value, resultEqualsValue)); } JSType getNativeType(JSTypeNative typeId) { return typeRegistry.getNativeType(typeId); } /** * If we definitely know what a type is based on the typeof result, * return it. Otherwise, return null. * * The typeof operation in JS is poorly defined, and this function works * for both the native typeof and goog.typeOf. It should not be made public, * because its semantics are informally defined, and would be wrong in * the general case. */ private JSType getNativeTypeForTypeOf(

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS>String value) { if (value.equals("number")) { return getNativeType(NUMBER_TYPE); } else if (value.equals("boolean")) { return getNativeType(BOOLEAN_TYPE); } else if (value.equals("string")) { return getNativeType(STRING_TYPE); } else if (value.equals("undefined")) { return getNativeType(VOID_TYPE); } else if (value.equals("function")) { return getNativeType(U2U_CONSTRUCTOR_TYPE); } else { return null; } } }

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS> ensureTyped(t, n); break; case Token.GET_REF: ensureTyped(t, n, getJSType(n.getFirstChild())); break; case Token.NULL: ensureTyped(t, n, NULL_TYPE); break; case Token.NUMBER: ensureTyped(t, n, NUMBER_TYPE); break; case Token.STRING: // Object literal keys are handled with OBJECTLIT if (!NodeUtil.isObjectLitKey(n, n.getParent())) { ensureTyped(t, n, STRING_TYPE); } break; case Token.GET: case Token.SET: // Object literal keys are handled with OBJECTLIT break; case Token.ARRAYLIT: ensureTyped(t, n, ARRAY_TYPE); break; case Token.REGEXP: ensureTyped(t, n, REGEXP_TYPE); break; case Token.GETPROP: visitGetProp(t, n, parent); typeable = !(parent.getType() == Token.ASSIGN && parent.getFirstChild() == n); break; case Token.GETELEM: visitGetElem(t, n); // The type of GETELEM is always unknown, so no point counting that. // If that unknown leaks elsewhere (say by an assignment to another // variable), then it will be counted. typeable = false; break; case Token.VAR: visitVar(t, n); typeable = false; break; case Token.NEW: visitNew(t, n); typeable = true; break; case Token.CALL: visitCall(t, n); typeable = !NodeUtil.isExpressionNode(parent); break; case Token.RETURN: visitReturn(t, n); typeable = false; break; case Token.DEC: case Token.INC: left = n.getFirstChild(); validator.expectNumber( t, left, getJSType(left), "increment/decrement"); ensureTyped(t, n, NUMBER_TYPE); break; case Token.NOT: ensureTyped(t, n, BOOLEAN_TYPE); break; case Token.VOID: ensureTyped(t, n, VOID_TYPE); break; case

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS> Token.TYPEOF: ensureTyped(t, n, STRING_TYPE); break; case Token.BITNOT: childType = getJSType(n.getFirstChild()); if (!childType.matchesInt32Context()) { report(t, n, BIT_OPERATION, NodeUtil.opToStr(n.getType()), childType.toString()); } ensureTyped(t, n, NUMBER_TYPE); break; case Token.POS: case Token.NEG: left = n.getFirstChild(); validator.expectNumber(t, left, getJSType(left), "sign operator"); ensureTyped(t, n, NUMBER_TYPE); break; case Token.EQ: case Token.NE: { leftType = getJSType(n.getFirstChild()); rightType = getJSType(n.getLastChild()); JSType leftTypeRestricted = leftType.restrictByNotNullOrUndefined(); JSType rightTypeRestricted = rightType.restrictByNotNullOrUndefined(); TernaryValue result = leftTypeRestricted.testForEquality(rightTypeRestricted); if (result != TernaryValue.UNKNOWN) { if (n.getType() == Token.NE) { result = result.not(); } report(t, n, DETERMINISTIC_TEST, leftType.toString(), rightType.toString(), result.toString()); } ensureTyped(t, n, BOOLEAN_TYPE); break; } case Token.SHEQ: case Token.SHNE: { leftType = getJSType(n.getFirstChild()); rightType = getJSType(n.getLastChild()); JSType leftTypeRestricted = leftType.restrictByNotNullOrUndefined(); JSType rightTypeRestricted = rightType.restrictByNotNullOrUndefined(); if (!leftTypeRestricted.canTestForShallowEqualityWith( rightTypeRestricted)) { report(t, n, DETERMINISTIC_TEST_NO_RESULT, leftType.toString(), rightType.toString()); } ensureTyped(t, n, BOOLEAN_TYPE); break; } case Token.LT: case Token.LE: case Token.GT: case Token.GE: leftType = getJSType(n.getFirstChild()); rightType = getJSType(n

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS> Token.OR: if (n.getJSType() != null) { // If we didn't run type inference. ensureTyped(t, n); } else { // If this is an enum, then give that type to the objectlit as well. if ((n.getType() == Token.OBJECTLIT) && (parent.getJSType() instanceof EnumType)) { ensureTyped(t, n, parent.getJSType()); } else { ensureTyped(t, n); } } if (n.getType() == Token.OBJECTLIT) { for (Node key : n.children()) { visitObjLitKey(t, key, n); } } break; default: report(t, n, UNEXPECTED_TOKEN, Token.name(n.getType())); ensureTyped(t, n); break; } // Don't count externs since the user's code may not even use that part. typeable = typeable && !inExterns; if (typeable) { doPercentTypedAccounting(t, n); } checkNoTypeCheckSection(n, false); } /** * Counts the given node in the typed statistics. * @param n a node that should be typed */ private void doPercentTypedAccounting(NodeTraversal t, Node n) { JSType type = n.getJSType(); if (type == null) { nullCount++; } else if (type.isUnknownType()) { if (reportUnknownTypes.isOn()) { compiler.report( t.makeError(n, reportUnknownTypes, UNKNOWN_EXPR_TYPE)); } unknownCount++; } else { typedCount++; } } /** * Visits an assignment <code>lvalue = rvalue</code>. If the * <code>lvalue</code> is a prototype modification, we change the schema * of the object type it is referring to. * @param t the traversal * @param assign the assign node * (<code>assign.getType() == Token.ASSIGN</code> is an implicit invariant) */ private void visitAssign(NodeTraversal t, Node assign) { JSDocInfo info = assign.getJSDocInfo(); Node lvalue = assign.

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS>Type.isInterface()) { checkDeclaredPropertyInheritance( t, assign, functionType, property, info, getJSType(rvalue)); } } else { // TODO(user): might want to flag that } return; } } // object.property = ...; ObjectType type = ObjectType.cast( objectJsType.restrictByNotNullOrUndefined()); if (type != null) { if (type.hasProperty(property) && !type.isPropertyTypeInferred(property) && !propertyIsImplicitCast(type, property)) { validator.expectCanAssignToPropertyOf( t, assign, getJSType(rvalue), type.getPropertyType(property), object, property); } return; } } else if (lvalue.getType() == Token.NAME) { // variable with inferred type case JSType rvalueType = getJSType(assign.getLastChild()); Var var = t.getScope().getVar(lvalue.getString()); if (var != null) { if (var.isTypeInferred()) { return; } } } // fall through case JSType leftType = getJSType(lvalue); Node rightChild = assign.getLastChild(); JSType rightType = getJSType(rightChild); if (validator.expectCanAssignTo( t, assign, rightType, leftType, "assignment")) { ensureTyped(t, assign, rightType); } else { ensureTyped(t, assign); } } /** * Visits an object literal field definition <code>key : value</code>. * * If the <code>lvalue</code> is a prototype modification, we change the * schema of the object type it is referring to. * * @param t the traversal * @param key the assign node */ private void visitObjLitKey(NodeTraversal t, Node key, Node objlit) { // TODO(johnlenz): Validate get and set function declarations are valid // as is the functions can have "extraneous" bits. // For getter and setter property definitions the // rvalue type != the property type. Node rvalue = key.getFirstChild(); JSType rightType = NodeUtil.getObjectLitKeyTypeFromValueType( key,

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS> getJSType(rvalue)); if (rightType == null) { rightType = getNativeType(UNKNOWN_TYPE); } Node owner = objlit; // Validate value is assignable to the key type. JSType keyType = getJSType(key); boolean valid = validator.expectCanAssignToPropertyOf(t, key, rightType, keyType, owner, NodeUtil.getObjectLitKeyName(key)); if (valid) { ensureTyped(t, key, rightType); } else { ensureTyped(t, key); } // Validate that the key type is assignable to the object property type. // This is necessary as the objlit may have been cast to a non-literal // object type. // TODO(johnlenz): consider introducing a CAST node to the AST (or // perhaps a parentheses node). JSType objlitType = getJSType(objlit); ObjectType type = ObjectType.cast( objlitType.restrictByNotNullOrUndefined()); if (type != null) { String property = NodeUtil.getObjectLitKeyName(key); if (type.hasProperty(property) && !type.isPropertyTypeInferred(property) && !propertyIsImplicitCast(type, property)) { validator.expectCanAssignToPropertyOf( t, key, keyType, type.getPropertyType(property), owner, property); } return; } } /** * Returns true if any type in the chain has an implictCast annotation for * the given property. */ private boolean propertyIsImplicitCast(ObjectType type, String prop) { for (; type != null; type = type.getImplicitPrototype()) { JSDocInfo docInfo = type.getOwnPropertyJSDocInfo(prop); if (docInfo != null && docInfo.isImplicitCast()) { return true; } } return false; } /** * Given a constructor type and a property name, check that the property has * the JSDoc annotation @override iff the property is declared on a * superclass. Several checks regarding inheritance correctness are also * performed. */ private void checkDeclaredPropertyInheritance( NodeTraversal t, Node n, FunctionType ctorType, String propertyName, JSDocInfo info, JSType propertyType

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS>) ? ", or " + abstractMethodName : ""; compiler.report( t.makeError(object, INVALID_INTERFACE_MEMBER_DECLARATION, abstractMethodMessage)); } if (assign.getLastChild().getType() == Token.FUNCTION && !NodeUtil.isEmptyBlock(assign.getLastChild().getLastChild())) { compiler.report( t.makeError(object, INTERFACE_FUNCTION_NOT_EMPTY, abstractMethodName)); } } /** * Visits an ASSIGN node for cases such as * <pre> * object.property = ...; * </pre> * that have an {@code @type} annotation. */ private void visitAnnotatedAssignGetprop(NodeTraversal t, Node assign, JSType type, Node object, String property, Node rvalue) { // verifying that the rvalue has the correct type validator.expectCanAssignToPropertyOf(t, assign, getJSType(rvalue), type, object, property); } /** * Visits a NAME node. * * @param t The node traversal object that supplies context, such as the * scope chain to use in name lookups as well as error reporting. * @param n The node being visited. * @param parent The parent of the node n. * @return whether the node is typeable or not */ boolean visitName(NodeTraversal t, Node n, Node parent) { // At this stage, we need to determine whether this is a leaf // node in an expression (which therefore needs to have a type // assigned for it) versus some other decorative node that we // can safely ignore. Function names, arguments (children of LP nodes) and // variable declarations are ignored. // TODO(user): remove this short-circuiting in favor of a // pre order traversal of the FUNCTION, CATCH, LP and VAR nodes. int parentNodeType = parent.getType(); if (parentNodeType == Token.FUNCTION || parentNodeType == Token.CATCH || parentNodeType == Token.LP || parentNodeType == Token.VAR) { return false; } JSType type = n.getJSType(); if (type == null) { type = getNativeType(UNKNOWN_TYPE); Var var = t.getScope().getVar(

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS>n.getString()); if (var != null) { JSType varType = var.getType(); if (varType != null) { type = varType; } } } ensureTyped(t, n, type); return true; } /** * Visits a GETPROP node. * * @param t The node traversal object that supplies context, such as the * scope chain to use in name lookups as well as error reporting. * @param n The node being visited. * @param parent The parent of <code>n</code> */ private void visitGetProp(NodeTraversal t, Node n, Node parent) { // GETPROP nodes have an assigned type on their node by the scope creator // if this is an enum declaration. The only namespaced enum declarations // that we allow are of the form object.name = ...; if (n.getJSType() != null && parent.getType() == Token.ASSIGN) { return; } // obj.prop or obj.method() // Lots of types can appear on the left, a call to a void function can // never be on the left. getPropertyType will decide what is acceptable // and what isn't. Node property = n.getLastChild(); Node objNode = n.getFirstChild(); JSType childType = getJSType(objNode); // TODO(user): remove in favor of flagging every property access on // non-object. if (!validator.expectNotNullOrUndefined(t, n, childType, childType + " has no properties", getNativeType(OBJECT_TYPE))) { ensureTyped(t, n); return; } checkPropertyAccess(childType, property.getString(), t, n); ensureTyped(t, n); } /** * Make sure that the access of this property is ok. */ private void checkPropertyAccess(JSType childType, String propName, NodeTraversal t, Node n) { ObjectType objectType = childType.dereference(); if (objectType != null) { JSType propType = getJSType(n); if ((!objectType.hasProperty(propName) || objectType.equals(typeRegistry.getNativeType(UNKNOWN_TYPE))) && propType.equals(

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS>typeRegistry.getNativeType(UNKNOWN_TYPE))) { if (objectType instanceof EnumType) { report(t, n, INEXISTENT_ENUM_ELEMENT, propName); } else if (!objectType.isEmptyType() && reportMissingProperties && !isPropertyTest(n)) { if (!typeRegistry.canPropertyBeDefined(objectType, propName)) { report(t, n, INEXISTENT_PROPERTY, propName, validator.getReadableJSTypeName(n.getFirstChild(), true)); } } } } else { // TODO(nicksantos): might want to flag the access on a non object when // it's impossible to get a property from this type. } } /** * Determines whether this node is testing for the existence of a property. * If true, we will not emit warnings about a missing property. * * @param getProp The GETPROP being tested. */ private boolean isPropertyTest(Node getProp) { Node parent = getProp.getParent(); switch (parent.getType()) { case Token.CALL: return parent.getFirstChild() != getProp && compiler.getCodingConvention().isPropertyTestFunction(parent); case Token.IF: case Token.WHILE: case Token.DO: case Token.FOR: return NodeUtil.getConditionExpression(parent) == getProp; case Token.INSTANCEOF: case Token.TYPEOF: return true; case Token.AND: case Token.HOOK: return parent.getFirstChild() == getProp; case Token.NOT: return parent.getParent().getType() == Token.OR && parent.getParent().getFirstChild() == parent; } return false; } /** * Visits a GETELEM node. * * @param t The node traversal object that supplies context, such as the * scope chain to use in name lookups as well as error reporting. * @param n The node being visited. */ private void visitGetElem(NodeTraversal t, Node n) { Node left = n.getFirstChild(); Node right = n.getLastChild(); validator.expectIndexMatch(t, n, getJSType(left), getJSType(right)); ensureTyped(t, n); }

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS> /** * Visits a VAR node. * * @param t The node traversal object that supplies context, such as the * scope chain to use in name lookups as well as error reporting. * @param n The node being visited. */ private void visitVar(NodeTraversal t, Node n) { // TODO(nicksantos): Fix this so that the doc info always shows up // on the NAME node. We probably want to wait for the parser // merge to fix this. JSDocInfo varInfo = n.hasOneChild() ? n.getJSDocInfo() : null; for (Node name : n.children()) { Node value = name.getFirstChild(); // A null var would indicate a bug in the scope creation logic. Var var = t.getScope().getVar(name.getString()); if (value != null) { JSType valueType = getJSType(value); JSType nameType = var.getType(); nameType = (nameType == null) ? getNativeType(UNKNOWN_TYPE) : nameType; JSDocInfo info = name.getJSDocInfo(); if (info == null) { info = varInfo; } if (info != null && info.hasEnumParameterType()) { // var.getType() can never be null, this would indicate a bug in the // scope creation logic. checkEnumInitializer( t, value, info.getEnumParameterType().evaluate(t.getScope(), typeRegistry)); } else if (var.isTypeInferred()) { ensureTyped(t, name, valueType); } else { validator.expectCanAssignTo( t, value, valueType, nameType, "initializing variable"); } } } } /** * Visits a NEW node. */ private void visitNew(NodeTraversal t, Node n) { Node constructor = n.getFirstChild(); FunctionType type = getFunctionType(constructor); if (type != null && type.isConstructor()) { visitParameterList(t, n, type); ensureTyped(t, n, type.getInstanceType()); } else { // TODO(user): add support for namespaced objects. if (constructor.getType() != Token.GETPROP) { // TODO(

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS> left, leftType, "bad left operand to bitwise operator"); validator.expectBitwiseable(t, right, rightType, "bad right operand to bitwise operator"); break; case Token.ASSIGN_ADD: case Token.ADD: break; default: report(t, n, UNEXPECTED_TOKEN, Node.tokenToName(op)); } ensureTyped(t, n); } /** * <p>Checks the initializer of an enum. An enum can be initialized with an * object literal whose values must be subtypes of the declared enum element * type, or by copying another enum.</p> * * <p>In the case of an enum copy, we verify that the enum element type of the * enum used for initialization is a subtype of the enum element type of * the enum the value is being copied in.</p> * * <p>Examples:</p> * <pre>var myEnum = {FOO: ..., BAR: ...}; * var myEnum = myOtherEnum;</pre> * * @param value the value used for initialization of the enum * @param primitiveType The type of each element of the enum. */ private void checkEnumInitializer( NodeTraversal t, Node value, JSType primitiveType) { if (value.getType() == Token.OBJECTLIT) { for (Node key = value.getFirstChild(); key != null; key = key.getNext()) { Node propValue = key.getFirstChild(); // the value's type must be assignable to the enum's primitive type validator.expectCanAssignTo( t, propValue, getJSType(propValue), primitiveType, "element type must match enum's type"); } } else if (value.getJSType() instanceof EnumType) { // TODO(user): Remove the instanceof check in favor // of a type.isEnumType() predicate. Currently, not all enum types are // implemented by the EnumClass, e.g. the unknown type and the any // type. The types need to be defined by interfaces such that an // implementation can implement multiple types interface. EnumType valueEnumType = (EnumType) value.getJSType(); JSType valueEnumPrimitiveType = valueEnumType.getElementsType().getPrimitiveType();

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS> validator.expectCanAssignTo(t, value, valueEnumPrimitiveType, primitiveType, "incompatible enum element types"); } else { // The error condition is handled in TypedScopeCreator. } } /** * This predicate is used to determine if the node represents an expression * that is a Reference according to JavaScript definitions. * * @param n The node being checked. * @return true if the sub-tree n is a reference, false otherwise. */ private static boolean isReference(Node n) { switch (n.getType()) { case Token.GETELEM: case Token.GETPROP: case Token.NAME: return true; default: return false; } } /** * This method gets the JSType from the Node argument and verifies that it is * present. */ private JSType getJSType(Node n) { JSType jsType = n.getJSType(); if (jsType == null) { // TODO(nicksantos): This branch indicates a compiler bug, not worthy of // halting the compilation but we should log this and analyze to track // down why it happens. This is not critical and will be resolved over // time as the type checker is extended. return getNativeType(UNKNOWN_TYPE); } else { return jsType; } } /** * Gets the type of the node or {@code null} if the node's type is not a * function. */ private FunctionType getFunctionType(Node n) { JSType type = getJSType(n).restrictByNotNullOrUndefined(); if (type.isUnknownType()) { return typeRegistry.getNativeFunctionType(U2U_CONSTRUCTOR_TYPE); } else if (type instanceof FunctionType) { return (FunctionType) type; } else { return null; } } // TODO(nicksantos): TypeCheck should never be attaching types to nodes. // All types should be attached by TypeInference. This is not true today // for legacy reasons. There are a number of places where TypeInference // doesn't attach a type, as a signal to TypeCheck that it needs to check // that node's type. /** * Ensure that the given node has a type. If it does not have one

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS>, * attach the UNKNOWN_TYPE. */ private void ensureTyped(NodeTraversal t, Node n) { ensureTyped(t, n, getNativeType(UNKNOWN_TYPE)); } private void ensureTyped(NodeTraversal t, Node n, JSTypeNative type) { ensureTyped(t, n, getNativeType(type)); } /** * Enforces type casts, and ensures the node is typed. * * A cast in the way that we use it in JSDoc annotations never * alters the generated code and therefore never can induce any runtime * operation. What this means is that a 'cast' is really just a compile * time constraint on the underlying value. In the future, we may add * support for run-time casts for compiled tests. * * To ensure some shred of sanity, we enforce the notion that the * type you are casting to may only meaningfully be a narrower type * than the underlying declared type. We also invalidate optimizations * on bad type casts. * * @param t The traversal object needed to report errors. * @param n The node getting a type assigned to it. * @param type The type to be assigned. */ private void ensureTyped(NodeTraversal t, Node n, JSType type) { // Make sure FUNCTION nodes always get function type. Preconditions.checkState(n.getType() != Token.FUNCTION || type instanceof FunctionType || type.isUnknownType()); JSDocInfo info = n.getJSDocInfo(); if (info != null) { if (info.hasType()) { JSType infoType = info.getType().evaluate(t.getScope(), typeRegistry); validator.expectCanCast(t, n, infoType, type); type = infoType; } if (info.isImplicitCast() && !inExterns) { String propName = n.getType() == Token.GETPROP ? n.getLastChild().getString() : "(missing)"; compiler.report( t.makeError(n, ILLEGAL_IMPLICIT_CAST, propName)); } } if (n.getJSType() == null) { n.setJSType(type); } } /** * Returns the percentage of

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS> return null; } private Node transform(AstNode node) { JSDocInfo jsDocInfo = handleJsDoc(node); Node irNode = justTransform(node); if (jsDocInfo != null) { irNode.setJSDocInfo(jsDocInfo); } setSourceInfo(irNode, node); return irNode; } private Node transformNameAsString(Name node) { JSDocInfo jsDocInfo = handleJsDoc(node); Node irNode = transformDispatcher.processName(node, true); if (jsDocInfo != null) { irNode.setJSDocInfo(jsDocInfo); } setSourceInfo(irNode, node); return irNode; } private Node transformNumberAsString(NumberLiteral literalNode) { JSDocInfo jsDocInfo = handleJsDoc(literalNode); Node irNode = newStringNode(getStringValue(literalNode.getNumber())); if (jsDocInfo != null) { irNode.setJSDocInfo(jsDocInfo); } setSourceInfo(irNode, literalNode); return irNode; } private static String getStringValue(double value) { long longValue = (long) value; // Return "1" instead of "1.0" if (longValue == value) { return Long.toString(longValue); } else { return Double.toString(value); } } private void setSourceInfo(Node irNode, AstNode node) { // If we have a named function, set the position to that of the name. if (irNode.getType() == Token.FUNCTION && irNode.getFirstChild().getLineno() != -1) { irNode.setLineno(irNode.getFirstChild().getLineno()); irNode.setCharno(irNode.getFirstChild().getCharno()); } else { if (irNode.getLineno() == -1) { // If we didn't already set the line, then set it now. This avoids // cases like ParenthesizedExpression where we just return a previous // node, but don't want the new node to get its parent's line number. int lineno = node.getLineno(); irNode.setLineno(lineno);

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS>transform(statementNode.getStatement())); return node; } @Override Node processName(Name nameNode) { return processName(nameNode, false); } Node processName(Name nameNode, boolean asString) { if (asString) { return newStringNode(Token.STRING, nameNode.getIdentifier()); } else { if (isReservedKeyword(nameNode.getIdentifier())) { errorReporter.error( "identifier is a reserved word", sourceName, nameNode.getLineno(), "", 0); } return newStringNode(Token.NAME, nameNode.getIdentifier()); } } /** * @return Whether the */ private boolean isReservedKeyword(String identifier) { return reservedKeywords != null && reservedKeywords.contains(identifier); } @Override Node processNewExpression(NewExpression exprNode) { return processFunctionCall(exprNode); } @Override Node processNumberLiteral(NumberLiteral literalNode) { return newNumberNode(literalNode.getNumber()); } @Override Node processObjectLiteral(ObjectLiteral literalNode) { if (literalNode.isDestructuring()) { reportDestructuringAssign(literalNode); } Node node = newNode(Token.OBJECTLIT); for (ObjectProperty el : literalNode.getElements()) { if (config.languageMode == LanguageMode.ECMASCRIPT3) { if (el.isGetter()) { reportGetter(el); continue; } else if (el.isSetter()) { reportSetter(el); continue; } } Node key = transformAsString(el.getLeft()); Node value = transform(el.getRight()); if (el.isGetter()) { key.setType(Token.GET); Preconditions.checkState(value.getType() == Token.FUNCTION); if (getFnParamNode(value).hasChildren()) { reportGetterParam(el.getLeft()); } } else if (el.isSetter()) { key.setType(Token.SET); Preconditions.checkState(value.getType() == Token.FUNCTION); if (!getFnParamNode(value).hasOneChild()) { reportSetterParam(el.getLeft()); } } key.addChildToFront(value); node.

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS>Block.getLineno()); } return node; } @Override Node processUnaryExpression(UnaryExpression exprNode) { int type = transformTokenType(exprNode.getType()); Node operand = transform(exprNode.getOperand()); if (type == Token.NEG && operand.getType() == Token.NUMBER) { operand.setDouble(-operand.getDouble()); return operand; } else { if (type == Token.INC || type == Token.DEC) { if (!validAssignmentTarget(operand)) { String msg = (type == Token.INC) ? "invalid increment target" : "invalid decrement target"; errorReporter.error( msg, sourceName, operand.getLineno(), "", 0); } } Node node = newNode(type, operand); if (exprNode.isPostfix()) { node.putBooleanProp(Node.INCRDECR_PROP, true); } return node; } } private boolean validAssignmentTarget(Node target) { switch (target.getType()) { case Token.NAME: case Token.GETPROP: case Token.GETELEM: return true; } return false; } @Override Node processVariableDeclaration(VariableDeclaration declarationNode) { if (!config.acceptConstKeyword && declarationNode.getType() == com.google.javascript.jscomp.mozilla.rhino.Token.CONST) { processIllegalToken(declarationNode); } Node node = newNode(Token.VAR); for (VariableInitializer child : declarationNode.getVariables()) { node.addChildToBack(transform(child)); } return node; } @Override Node processVariableInitializer(VariableInitializer initializerNode) { Node node = transform(initializerNode.getTarget()); if (initializerNode.getInitializer() != null) { node.addChildToBack(transform(initializerNode.getInitializer())); node.setLineno(node.getLineno()); } return node; } @Override Node processWhileLoop(WhileLoop loopNode) { return newNode( Token.WHILE, transform(loopNode.getCondition()), transformBlock(loopNode.getBody())); } @Override Node processWithStatement(WithStatement statementNode) { return newNode( Token.

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS>Token.DIV: return Token.DIV; case com.google.javascript.jscomp.mozilla.rhino.Token.MOD: return Token.MOD; case com.google.javascript.jscomp.mozilla.rhino.Token.NOT: return Token.NOT; case com.google.javascript.jscomp.mozilla.rhino.Token.BITNOT: return Token.BITNOT; case com.google.javascript.jscomp.mozilla.rhino.Token.POS: return Token.POS; case com.google.javascript.jscomp.mozilla.rhino.Token.NEG: return Token.NEG; case com.google.javascript.jscomp.mozilla.rhino.Token.NEW: return Token.NEW; case com.google.javascript.jscomp.mozilla.rhino.Token.DELPROP: return Token.DELPROP; case com.google.javascript.jscomp.mozilla.rhino.Token.TYPEOF: return Token.TYPEOF; case com.google.javascript.jscomp.mozilla.rhino.Token.GETPROP: return Token.GETPROP; case com.google.javascript.jscomp.mozilla.rhino.Token.SETPROP: return Token.SETPROP; case com.google.javascript.jscomp.mozilla.rhino.Token.GETELEM: return Token.GETELEM; case com.google.javascript.jscomp.mozilla.rhino.Token.SETELEM: return Token.SETELEM; case com.google.javascript.jscomp.mozilla.rhino.Token.CALL: return Token.CALL; case com.google.javascript.jscomp.mozilla.rhino.Token.NAME: return Token.NAME; case com.google.javascript.jscomp.mozilla.rhino.Token.NUMBER: return Token.NUMBER; case com.google.javascript.jscomp.mozilla.rhino.Token.STRING: return Token.STRING; case com.google.javascript.jscomp.mozilla.rhino.Token.NULL: return Token.NULL; case com.google.javascript.jscomp.mozilla.rhino.Token.THIS: return Token.THIS; case com.google.javascript.jscomp.mozilla.rhino.Token.FALSE

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS> create nodes and set the initial node properties. private Node newNode(int type) { return new Node(type).clonePropsFrom(templateNode); } private Node newNode(int type, Node child1) { return new Node(type, child1).clonePropsFrom(templateNode); } private Node newNode(int type, Node child1, Node child2) { return new Node(type, child1, child2).clonePropsFrom(templateNode); } private Node newNode(int type, Node child1, Node child2, Node child3) { return new Node(type, child1, child2, child3).clonePropsFrom(templateNode); } private Node newStringNode(String value) { return Node.newString(value).clonePropsFrom(templateNode); } private Node newStringNode(int type, String value) { return Node.newString(type, value).clonePropsFrom(templateNode); } private Node newNumberNode(Double value) { return Node.newNumber(value).clonePropsFrom(templateNode); } }

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS>/* * Copyright 2008 The Closure Compiler Authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.javascript.jscomp.CheckLevel; /** * Sets the level for a particular DiagnosticGroup. * @author nicksantos@google.com (Nick Santos) */ public class DiagnosticGroupWarningsGuard extends WarningsGuard { private final DiagnosticGroup group; private final CheckLevel level; public DiagnosticGroupWarningsGuard( DiagnosticGroup group, CheckLevel level) { this.group = group; this.level = level; } @Override public CheckLevel level(JSError error) { return group.matches(error) ? level : null; } @Override public boolean disables(DiagnosticGroup otherGroup) { return !level.isOn() && group.isSubGroup(otherGroup); } @Override public boolean enables(DiagnosticGroup otherGroup) { if (level.isOn()) { for (DiagnosticType type : otherGroup.getTypes()) { if (group.matches(type)) { return true; } } } return false; } @Override public String toString() { return group + "(" + level + ")"; } }

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS> return implicitPrototype.isPropertyTypeInferred(property); } // property does not exist return false; } return p.inferred; } @Override public JSType getPropertyType(String propertyName) { Property p = properties.get(propertyName); if (p != null) { return p.type; } ObjectType implicitPrototype = getImplicitPrototype(); if (implicitPrototype != null) { return implicitPrototype.getPropertyType(propertyName); } return getNativeType(JSTypeNative.UNKNOWN_TYPE); } @Override public boolean isPropertyInExterns(String propertyName) { Property p = properties.get(propertyName); if (p != null) { return p.inExterns; } ObjectType implicitPrototype = getImplicitPrototype(); if (implicitPrototype != null) { return implicitPrototype.isPropertyInExterns(propertyName); } return false; } @Override boolean defineProperty(String name, JSType type, boolean inferred, boolean inExterns, Node propertyNode) { if (hasOwnDeclaredProperty(name)) { return false; } properties.put(name, new Property(type, inferred, inExterns, propertyNode)); return true; } @Override public Node getPropertyNode(String propertyName) { Property p = properties.get(propertyName); if (p != null) { return p.propertyNode; } ObjectType implicitPrototype = getImplicitPrototype(); if (implicitPrototype != null) { return implicitPrototype.getPropertyNode(propertyName); } return null; } @Override public JSDocInfo getOwnPropertyJSDocInfo(String propertyName) { Property p = properties.get(propertyName); if (p != null) { return p.docInfo; } return null; } @Override public void setPropertyJSDocInfo(String propertyName, JSDocInfo info, boolean inExterns) { if (info != null) { if (!properties.containsKey(propertyName)) { // If docInfo was attached, but the type of the property // was not defined anywhere, then we consider this an explicit // declaration of the property. defineInferredProperty(propertyName, getPropertyType(propertyName), inExterns, null);

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS> return RecordType.isSubtype(this, (RecordType) that); } // Interfaces // Find all the interfaces implemented by this class and compare each one // to the interface instance. ObjectType thatObj = that.toObjectType(); ObjectType thatCtor = thatObj == null ? null : thatObj.getConstructor(); if (thatCtor != null && thatCtor.isInterface()) { Iterable<ObjectType> thisInterfaces = getCtorImplementedInterfaces(); for (ObjectType thisInterface : thisInterfaces) { if (thisInterface.isSubtype(that)) { return true; } } } // other prototype based objects if (that != null) { if (isUnknownType() || implicitPrototypeChainIsUnknown()) { // If unsure, say 'yes', to avoid spurious warnings. // TODO(user): resolve the prototype chain completely in all cases, // to avoid guessing. return true; } return this.isImplicitPrototype(thatObj); } return false; } private boolean implicitPrototypeChainIsUnknown() { ObjectType p = getImplicitPrototype(); while (p != null) { if (p.isUnknownType()) { return true; } p = p.getImplicitPrototype(); } return false; } private static final class Property implements Serializable { private static final long serialVersionUID = 1L; /** * Property's type. */ private JSType type; /** * Whether the property's type is inferred. */ private final boolean inferred; /** * Whether the property is defined in the externs. */ private final boolean inExterns; /** * The node corresponding to this property, e.g., a GETPROP node that * declares this property. */ private final Node propertyNode; /** The JSDocInfo for this property. */ private JSDocInfo docInfo = null; private Property(JSType type, boolean inferred, boolean inExterns, Node propertyNode) { this.type = type; this.inferred = inferred; this.inExterns = inExterns; this.propertyNode = propertyNode; } } @Override public boolean hasCachedValues() { return super.hasCachedValues(); } /** Whether this is a

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS> built-in object. */ @Override public boolean isNativeObjectType() { return nativeType; } @Override JSType resolveInternal(ErrorReporter t, StaticScope<JSType> scope) { setResolvedTypeInternal(this); ObjectType implicitPrototype = getImplicitPrototype(); if (implicitPrototype != null) { implicitPrototypeFallback = (ObjectType) implicitPrototype.resolve(t, scope); } for (Property prop : properties.values()) { prop.type = safeResolve(prop.type, t, scope); } return this; } }

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS> if the object is named. * @return true if the object is named, false if it is anonymous */ public boolean hasReferenceName() { return false; } @Override public TernaryValue testForEquality(JSType that) { // super TernaryValue result = super.testForEquality(that); if (result != null) { return result; } // objects are comparable to everything but null/undefined if (that.isSubtype( getNativeType(JSTypeNative.OBJECT_NUMBER_STRING_BOOLEAN))) { return UNKNOWN; } else { return FALSE; } } /** * Gets this object's constructor. * @return this object's constructor or {@code null} if it is a native * object (constructed natively v.s. by instantiation of a function) */ public abstract FunctionType getConstructor(); /** * Gets the implicit prototype (a.k.a. the {@code [[Prototype]]} property). */ public abstract ObjectType getImplicitPrototype(); /** * Defines a property whose type is synthesized (i.e. not inferred). * @param propertyName the property's name * @param type the type * @param inExterns {@code true} if this property was defined in an externs * file. TightenTypes assumes that any function passed to an externs * property could be called, so setting this incorrectly could result * in live code being removed. * @param propertyNode the node corresponding to the declaration of property * which might later be accessed using {@code getPropertyNode}. */ public final boolean defineDeclaredProperty(String propertyName, JSType type, boolean inExterns, Node propertyNode) { boolean result = defineProperty(propertyName, type, false, inExterns, propertyNode); // All property definitions go through this method // or defineDeclaredProperty. Because the properties defined an an // object can affect subtyping, it's slightly more efficient // to register this after defining the property. registry.registerPropertyOnType(propertyName, this); return result; } /** * Defines a property whose type is inferred. * @param propertyName the property's name * @param type the type * @param inExterns {@code true} if this property

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS> was defined in an externs * file. TightenTypes assumes that any function passed to an externs * property could be called, so setting this incorrectly could result * in live code being removed. * @param propertyNode the node corresponding to the inferred definition of * property that might later be accessed using {@code getPropertyNode}. */ public final boolean defineInferredProperty(String propertyName, JSType type, boolean inExterns, Node propertyNode) { if (hasProperty(propertyName)) { JSType originalType = getPropertyType(propertyName); type = originalType == null ? type : originalType.getLeastSupertype(type); } boolean result = defineProperty(propertyName, type, true, inExterns, propertyNode); // All property definitions go through this method // or defineDeclaredProperty. Because the properties defined an an // object can affect subtyping, it's slightly more efficient // to register this after defining the property. registry.registerPropertyOnType(propertyName, this); return result; } /** * Defines a property.<p> * * For clarity, callers should prefer {@link #defineDeclaredProperty} and * {@link #defineInferredProperty}. * * @param propertyName the property's name * @param type the type * @param inferred {@code true} if this property's type is inferred * @param inExterns {@code true} if this property was defined in an externs * file. TightenTypes assumes that any function passed to an externs * property could be called, so setting this incorrectly could result * in live code being removed. * @param propertyNode the node that represents the definition of property. * Depending on the actual sub-type the node type might be different. * The general idea is to have an estimate of where in the source code * this property is defined. * @return True if the property was registered successfully, false if this * conflicts with a previous property type declaration. */ abstract boolean defineProperty(String propertyName, JSType type, boolean inferred, boolean inExterns, Node propertyNode); /** * Gets the node corresponding to the definition of the specified property. * This could be the node corresponding to declaration of the property or

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS> public BooleanLiteralSet getPossibleToBooleanOutcomes() { return BooleanLiteralSet.TRUE; } /** * We treat this as the unknown type if any of its implicit prototype * properties is unknown. */ @Override public boolean isUnknownType() { // If the object is unknown now, check the supertype again, // because it might have been resolved since the last check. if (unknown) { ObjectType implicitProto = getImplicitPrototype(); if (implicitProto == null || implicitProto.isNativeObjectType()) { unknown = false; } else { unknown = implicitProto.isUnknownType(); } } return unknown; } @Override public boolean isObject() { return true; } /** * Returns true if any cached valeus have been set for this type. If true, * then the prototype chain should not be changed, as it might invalidate the * cached values. */ public boolean hasCachedValues() { return !unknown; } /** * Clear cached values. Should be called before making changes to a prototype * that may have been changed since creation. */ public void clearCachedValues() { unknown = true; } /** Whether this is a built-in object. */ public boolean isNativeObjectType() { return false; } /** * A null-safe version of JSType#toObjectType. */ public static ObjectType cast(JSType type) { return type == null ? null : type.toObjectType(); } /** * Gets the interfaces implemented by the ctor associated with this type. * Intended to be overridden by subclasses. */ public Iterable<ObjectType> getCtorImplementedInterfaces() { return ImmutableSet.of(); } }

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS>/* * Copyright 2008 The Closure Compiler Authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Maps; import com.google.common.collect.Sets; import java.util.Arrays; import java.util.Collection; import java.util.Map; import java.util.Set; /** * Group a set of related diagnostic types together, so that they can * be toggled on and off as one unit. * @author nicksantos@google.com (Nick Santos) */ public class DiagnosticGroup { // The set of types represented by this group, hashed by key. private final Set<DiagnosticType> types; // A human-readable name for the group. private final String name; /** * Create a group that matches all errors of the given types. */ DiagnosticGroup(String name, DiagnosticType ...types) { this.name = name; this.types = ImmutableSet.copyOf(Arrays.asList(types)); } /** * Create a group that matches all errors of the given types. */ public DiagnosticGroup(DiagnosticType ...types) { this(null, types); } /** * Create a diagnostic group with no name that only matches the given type. */ private DiagnosticGroup(DiagnosticType type) { this.name = null; this.types = ImmutableSet.of(type); } // DiagnosticGroups with only a single DiagnosticType. private static final Map<DiagnosticType, DiagnosticGroup> singletons = Maps.newHashMap(); /** Create a diagnostic group that matches only the given type

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS>. */ static DiagnosticGroup forType(DiagnosticType type) { if (!singletons.containsKey(type)) { singletons.put(type, new DiagnosticGroup(type)); } return singletons.get(type); } /** * Create a composite group. */ public DiagnosticGroup(DiagnosticGroup ...groups) { this(null, groups); } /** * Create a composite group. */ public DiagnosticGroup(String name, DiagnosticGroup ...groups) { Set<DiagnosticType> set = Sets.newHashSet(); for (DiagnosticGroup group : groups) { set.addAll(group.types); } this.name = name; this.types = ImmutableSet.copyOf(set); } /** * Returns whether the given error's type matches a type * in this group. */ public boolean matches(JSError error) { return matches(error.getType()); } /** * Returns whether the given type matches a type in this group. */ public boolean matches(DiagnosticType type) { return types.contains(type); } /** * Returns whether all of the types in the given group are in this group. */ boolean isSubGroup(DiagnosticGroup group) { for (DiagnosticType type : group.types) { if (!matches(type)) { return false; } } return true; } /** * Returns an iterator over all the types in this group. */ Collection<DiagnosticType> getTypes() { return types; } public String toString() { return name == null ? super.toString() : "DiagnosticGroup<" + name + ">"; } }

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS>) { super(registry, registry.getNativeObjectType(JSTypeNative.UNKNOWN_TYPE)); Preconditions.checkNotNull(reference); this.reference = reference; this.sourceName = sourceName; this.lineno = lineno; this.charno = charno; } @Override boolean defineProperty(String propertyName, JSType type, boolean inferred, boolean inExterns, Node propertyNode) { if (!isResolved()) { // If this is an unresolved object type, we need to save all its // properties and define them when it is resolved. if (propertyContinuations == null) { propertyContinuations = Lists.newArrayList(); } propertyContinuations.add( new PropertyContinuation( propertyName, type, inferred, inExterns, propertyNode)); return true; } else { return super.defineProperty( propertyName, type, inferred, inExterns, propertyNode); } } private void finishPropertyContinuations() { ObjectType referencedObjType = getReferencedObjTypeInternal(); if (referencedObjType != null && !referencedObjType.isUnknownType()) { if (propertyContinuations != null) { for (PropertyContinuation c : propertyContinuations) { c.commit(this); } } } propertyContinuations = null; } /** Returns the type to which this refers (which is unknown if unresolved). */ public JSType getReferencedType() { return getReferencedTypeInternal(); } @Override public String getReferenceName() { return reference; } @Override public String toString() { return reference; } @Override public boolean hasReferenceName() { return true; } @Override boolean isNamedType() { return true; } @Override public boolean isNominalType() { return true; } /** * Two named types are equivalent if they are the same {@code * ObjectType} object. This is complicated by the fact that isEquivalent * is sometimes called before we have a chance to resolve the type * names. * * @return {@code true} iff {@code that} == {@code this} or {@code that} * is a {@link NamedType} whose reference is the same as ours, * or {@code that} is the type we reference

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS>. */ @Override public boolean isEquivalentTo(JSType that) { if (this == that) { return true; } ObjectType objType = ObjectType.cast(that); if (objType != null) { return objType.isNominalType() && reference.equals(objType.getReferenceName()); } return false; } @Override public int hashCode() { return reference.hashCode(); } /** * Resolve the referenced type within the enclosing scope. */ @Override JSType resolveInternal(ErrorReporter t, StaticScope<JSType> enclosing) { // TODO(user): Investigate whether it is really necessary to keep two // different mechanisms for resolving named types, and if so, which order // makes more sense. Now, resolution via registry is first in order to // avoid triggering the warnings built into the resolution via properties. boolean resolved = resolveViaRegistry(t, enclosing); if (detectImplicitPrototypeCycle()) { handleTypeCycle(t); } if (resolved) { super.resolveInternal(t, enclosing); finishPropertyContinuations(); return registry.isLastGeneration() ? getReferencedType() : this; } resolveViaProperties(t, enclosing); if (detectImplicitPrototypeCycle()) { handleTypeCycle(t); } super.resolveInternal(t, enclosing); if (isResolved()) { finishPropertyContinuations(); } return registry.isLastGeneration() ? getReferencedType() : this; } /** * Resolves a named type by looking it up in the registry. * @return True if we resolved successfully. */ private boolean resolveViaRegistry( ErrorReporter t, StaticScope<JSType> enclosing) { JSType type = registry.getType(reference); if (type != null) { setReferencedAndResolvedType(type, t, enclosing); return true; } return false; } /** * Resolves a named type by looking up its first component in the scope, and * subsequent components as properties. The scope must have been fully * parsed and a symbol table constructed. */ private void resolveViaProperties(ErrorReporter t, StaticScope<JSType> enclosing) { JSType value = lookupViaProperties

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS>(t, enclosing); // last component of the chain if ((value instanceof FunctionType) && (value.isConstructor() || value.isInterface())) { FunctionType functionType = (FunctionType) value; setReferencedAndResolvedType( functionType.getInstanceType(), t, enclosing); } else if (value instanceof EnumType) { setReferencedAndResolvedType( ((EnumType) value).getElementsType(), t, enclosing); } else { // We've been running into issues where people forward-declare // non-named types. (This is legitimate...our dependency management // code doubles as our forward-declaration code.) // // So if the type does resolve to an actual value, but it's not named, // then don't respect the forward declaration. handleUnresolvedType(t, value == null || value.isUnknownType()); } } /** * Resolves a type by looking up its first component in the scope, and * subsequent components as properties. The scope must have been fully * parsed and a symbol table constructed. * @return The type of the symbol, or null if the type could not be found. */ private JSType lookupViaProperties( ErrorReporter t, StaticScope<JSType> enclosing) { String[] componentNames = reference.split("\\.", -1); if (componentNames[0].length() == 0) { return null; } StaticSlot<JSType> slot = enclosing.getSlot(componentNames[0]); if (slot == null) { return null; } // If the first component has a type of 'Unknown', then any type // names using it should be regarded as silently 'Unknown' rather than be // noisy about it. JSType slotType = slot.getType(); if (slotType == null || slotType.isAllType() || slotType.isNoType()) { return null; } JSType value = getTypedefType(t, slot, componentNames[0]); if (value == null) { return null; } // resolving component by component for (int i = 1; i < componentNames.length; i++) { ObjectType parentClass = ObjectType.cast(value); if (parentClass == null) { return null

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS>; } if (componentNames[i].length() == 0) { return null; } value = parentClass.getPropertyType(componentNames[i]); } return value; } private void setReferencedAndResolvedType(JSType type, ErrorReporter t, StaticScope<JSType> enclosing) { if (validator != null) { validator.apply(type); } setReferencedType(type); checkEnumElementCycle(t); setResolvedTypeInternal(getReferencedType()); } private void handleTypeCycle(ErrorReporter t) { setReferencedType( registry.getNativeObjectType(JSTypeNative.UNKNOWN_TYPE)); t.warning("Cycle detected in inheritance chain of type " + reference, sourceName, lineno, null, charno); setResolvedTypeInternal(getReferencedType()); } private void checkEnumElementCycle(ErrorReporter t) { JSType referencedType = getReferencedType(); if (referencedType instanceof EnumElementType && ((EnumElementType) referencedType).getPrimitiveType() == this) { handleTypeCycle(t); } } // Warns about this type being unresolved iff it's not a forward-declared // type name. private void handleUnresolvedType( ErrorReporter t, boolean ignoreForwardReferencedTypes) { if (registry.isLastGeneration()) { boolean isForwardDeclared = ignoreForwardReferencedTypes && registry.isForwardDeclaredType(reference); if (!isForwardDeclared && registry.isLastGeneration()) { t.warning("Bad type annotation. Unknown type " + reference, sourceName, lineno, null, charno); } else { setReferencedType( registry.getNativeObjectType( JSTypeNative.NO_RESOLVED_TYPE)); if (registry.isLastGeneration() && validator != null) { validator.apply(getReferencedType()); } } setResolvedTypeInternal(getReferencedType()); } else { setResolvedTypeInternal(this); } } JSType getTypedefType(ErrorReporter t, StaticSlot<JSType> slot, String name) { JSType type = slot.getType(); if (type != null) { return type; } handleUnresolvedType(t, true); return null; } @Override public boolean

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS> setValidator(Predicate<JSType> validator) { // If the type is already resolved, we can validate it now. If // the type has not been resolved yet, we need to wait till its // resolved before we can validate it. if (this.isResolved()) { return super.setValidator(validator); } else { this.validator = validator; return true; } } /** Store enough information to define a property at a later time. */ private static final class PropertyContinuation { private final String propertyName; private final JSType type; private final boolean inferred; private final boolean inExterns; private final Node propertyNode; private PropertyContinuation( String propertyName, JSType type, boolean inferred, boolean inExterns, Node propertyNode) { this.propertyName = propertyName; this.type = type; this.inferred = inferred; this.inExterns = inExterns; this.propertyNode = propertyNode; } void commit(ObjectType target) { target.defineProperty( propertyName, type, inferred, inExterns, propertyNode); } } }

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS> */ boolean skipRenaming; /** Set of nodes for this field that need renaming. */ Set<Node> renameNodes = Sets.newHashSet(); /** * Map from node to the highest type in the prototype chain containing the * field for that node. In the case of a union, the type is the highest type * of one of the types in the union. */ final Map<Node, T> rootTypes = Maps.newHashMap(); Property(String name) { this.name = name; } /** Returns the types on which this field is referenced. */ UnionFind<T> getTypes() { if (types == null) { types = new StandardUnionFind<T>(); } return types; } /** * Record that this property is referenced from this type. * @return true if the type was recorded for this property, else false, * which would happen if the type was invalidating. */ boolean addType(T type, T top, T relatedType) { checkState(!skipRenaming, "Attempt to record skipped property: %s", name); if (typeSystem.isInvalidatingType(top)) { invalidate(); return false; } else { if (typeSystem.isTypeToSkip(top)) { addTypeToSkip(top); } if (relatedType == null) { getTypes().add(top); } else { getTypes().union(top, relatedType); } typeSystem.recordInterfaces(type, top, this); return true; } } /** Records the given type as one to skip for this property. */ void addTypeToSkip(T type) { for (T skipType : typeSystem.getTypesToSkipForType(type)) { typesToSkip.add(skipType); getTypes().union(skipType, type); } } /** Invalidates any types related to invalid types. */ void expandTypesToSkip() { // If we are not going to rename any properties, then we do not need to // update the list of invalid types, as they are all invalid. if (shouldRename()) { int count = 0; while (true) { // It should usually only take one time through this do-while. checkState(++

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS>count < 10, "Stuck in loop expanding types to skip."); // Make sure that the representative type for each type to skip is // marked as being skipped. Set<T> rootTypesToSkip = Sets.newHashSet(); for (T subType : typesToSkip) { rootTypesToSkip.add(types.find(subType)); } typesToSkip.addAll(rootTypesToSkip); Set<T> newTypesToSkip = Sets.newHashSet(); Set<T> allTypes = types.elements(); int originalTypesSize = allTypes.size(); for (T subType : allTypes) { if (!typesToSkip.contains(subType) && typesToSkip.contains(types.find(subType))) { newTypesToSkip.add(subType); } } for (T newType : newTypesToSkip) { addTypeToSkip(newType); } // If there were not any new types added, we are done here. if (types.elements().size() == originalTypesSize) { break; } } } } /** Returns true if any instance of this property should be renamed. */ boolean shouldRename() { return !skipRenaming && types != null && types.allEquivalenceClasses().size() > 1; } /** * Returns true if this property should be renamed on this type. * expandTypesToSkip() should be called before this, if anything has been * added to the typesToSkip list. */ boolean shouldRename(T type) { return !skipRenaming && !typesToSkip.contains(type); } /** * Invalidates a field from renaming. Used for field references on an * object with unknown type. */ boolean invalidate() { boolean changed = !skipRenaming; skipRenaming = true; types = null; return changed; } /** * Schedule the node to potentially be renamed. * @param node the node to rename * @param type the highest type in the prototype chain for which the * property is defined * @return True if type was accepted without invalidation or if the property * was already invalidated. False if this property was invalidated this * time. */

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS> boolean scheduleRenaming(Node node, T type) { if (!skipRenaming) { if (typeSystem.isInvalidatingType(type)) { invalidate(); return false; } renameNodes.add(node); rootTypes.put(node, type); } return true; } } private Map<String, Property> properties = Maps.newHashMap(); static DisambiguateProperties<JSType> forJSTypeSystem( AbstractCompiler compiler) { return new DisambiguateProperties<JSType>( compiler, new JSTypeSystem(compiler)); } static DisambiguateProperties<ConcreteType> forConcreteTypeSystem( AbstractCompiler compiler, TightenTypes tt) { return new DisambiguateProperties<ConcreteType>( compiler, new ConcreteTypeSystem(tt, compiler.getCodingConvention())); } /** * This constructor should only be called by one of the helper functions * above for either the JSType system, or the concrete type system. */ private DisambiguateProperties(AbstractCompiler compiler, TypeSystem<T> typeSystem) { this.compiler = compiler; this.typeSystem = typeSystem; this.showInvalidationWarnings = compiler.getErrorLevel( JSError.make("", 0, 0, Warnings.INVALIDATION)) != CheckLevel.OFF; } public void process(Node externs, Node root) { for (TypeMismatch mis : compiler.getTypeValidator().getMismatches()) { addInvalidatingType(mis.typeA); addInvalidatingType(mis.typeB); } StaticScope<T> scope = typeSystem.getRootScope(); NodeTraversal.traverse(compiler, externs, new FindExternProperties()); NodeTraversal.traverse(compiler, root, new FindRenameableProperties()); renameProperties(); } /** * Invalidates the given type, so that no properties on it will be renamed. */ private void addInvalidatingType(JSType type) { type = type.restrictByNotNullOrUndefined(); if (type instanceof UnionType) { for (JSType alt : ((UnionType) type).getAlternates()) { addInvalidatingType(alt); } return; } typeSystem.addInvalidatingType(type); ObjectType objType

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS> = ObjectType.cast(type); if (objType != null && objType.getImplicitPrototype() != null) { typeSystem.addInvalidatingType(objType.getImplicitPrototype()); } } /** Returns the property for the given name, creating it if necessary. */ protected Property getProperty(String name) { if (!properties.containsKey(name)) { properties.put(name, new Property(name)); } return properties.get(name); } /** Public for testing. */ T getTypeWithProperty(String field, T type) { return typeSystem.getTypeWithProperty(field, type); } /** Tracks the current type system scope while traversing. */ private abstract class AbstractScopingCallback implements ScopedCallback { protected final Stack<StaticScope<T>> scopes = new Stack<StaticScope<T>>(); public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) { return true; } public void enterScope(NodeTraversal t) { if (t.inGlobalScope()) { scopes.push(typeSystem.getRootScope()); } else { scopes.push(typeSystem.getFunctionScope(t.getScopeRoot())); } } public void exitScope(NodeTraversal t) { scopes.pop(); } /** Returns the current scope at this point in the file. */ protected StaticScope<T> getScope() { return scopes.peek(); } } /** * Finds all properties defined in the externs file and sets them as * ineligible for renaming from the type on which they are defined. */ private class FindExternProperties extends AbstractScopingCallback { @Override public void visit(NodeTraversal t, Node n, Node parent) { // TODO(johnlenz): Support object-literal property definitions. if (n.getType() == Token.GETPROP) { String field = n.getLastChild().getString(); T type = typeSystem.getType(getScope(), n.getFirstChild(), field); Property prop = getProperty(field); if (typeSystem.isInvalidatingType(type)) { prop.invalidate(); } else { prop.addTypeToSkip(type); // If this is a prototype property, then we want to skip assignments // to the instance type as

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS> well. These assignments are not usually // seen in the extern code itself, so we must handle them here. if ((type = typeSystem.getInstanceFromPrototype(type)) != null) { prop.getTypes().add(type); prop.typesToSkip.add(type); } } } } } /** * Traverses the tree, building a map from field names to Nodes for all * fields that can be renamed. */ private class FindRenameableProperties extends AbstractScopingCallback { @Override public void visit(NodeTraversal t, Node n, Node parent) { if (n.getType() == Token.GETPROP) { handleGetProp(t, n); } else if (n.getType() == Token.OBJECTLIT) { handleObjectLit(t, n); } } /** * Processes a GETPROP node. */ private void handleGetProp(NodeTraversal t, Node n) { String name = n.getLastChild().getString(); T type = typeSystem.getType(getScope(), n.getFirstChild(), name); Property prop = getProperty(name); if (!prop.scheduleRenaming(n.getLastChild(), processProperty(t, prop, type, null))) { if (showInvalidationWarnings) { compiler.report(JSError.make( t.getSourceName(), n, Warnings.INVALIDATION, name, (type == null ? "null" : type.toString()), n.toString())); } } } /** * Processes a OBJECTLIT node. */ private void handleObjectLit(NodeTraversal t, Node n) { Node child = n.getFirstChild(); while (child != null) { // Maybe STRING, GET, SET // We should never see a mix of numbers and strings. String name = child.getString(); T type = typeSystem.getType(getScope(), n, name); Property prop = getProperty(name); if (!prop.scheduleRenaming(child, processProperty(t, prop, type, null))) { if (showInvalidationWarnings) { compiler.report(JSError.make( t.getSourceName(), child, Warnings.INVALIDATION, name, (type == null ? "null" : type.toString()), n.

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS>toString())); } } child = child.getNext(); } } /** * Processes a property, adding it to the list of properties to rename. * @return a representative type for the property reference, which will be * the highest type on the prototype chain of the provided type. In the * case of a union type, it will be the highest type on the prototype * chain of one of the members of the union. */ private T processProperty( NodeTraversal t, Property prop, T type, T relatedType) { type = typeSystem.restrictByNotNullOrUndefined(type); if (prop.skipRenaming || typeSystem.isInvalidatingType(type)) { return null; } Iterable<T> alternatives = typeSystem.getTypeAlternatives(type); if (alternatives != null) { T firstType = relatedType; for (T subType : alternatives) { T lastType = processProperty(t, prop, subType, firstType); if (lastType != null) { firstType = firstType == null ? lastType : firstType; } } return firstType; } else { T topType = typeSystem.getTypeWithProperty(prop.name, type); if (typeSystem.isInvalidatingType(topType)) { return null; } prop.addType(type, topType, relatedType); return topType; } } } /** Renames all properties with references on more than one type. */ void renameProperties() { int propsRenamed = 0, propsSkipped = 0, instancesRenamed = 0, instancesSkipped = 0, singleTypeProps = 0; for (Property prop : properties.values()) { if (prop.shouldRename()) { Map<T, String> propNames = buildPropNames(prop.getTypes(), prop.name); ++propsRenamed; prop.expandTypesToSkip(); UnionFind<T> types = prop.getTypes(); for (Node node : prop.renameNodes) { T rootType = prop.rootTypes.get(node); if (prop.shouldRename(rootType)) { String newName = propNames.get(rootType); node.setString(newName); compiler

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS>.reportCodeChange(); ++instancesRenamed; } else { ++instancesSkipped; } } } else { if (prop.skipRenaming) { ++propsSkipped; } else { ++singleTypeProps; } } } logger.info("Renamed " + instancesRenamed + " instances of " + propsRenamed + " properties."); logger.info("Skipped renaming " + instancesSkipped + " invalidated " + "properties, " + propsSkipped + " instances of properties " + "that were skipped for specific types and " + singleTypeProps + " properties that were referenced from only one type."); } /** * Chooses a name to use for renaming in each equivalence class and maps * each type in that class to it. */ private Map<T, String> buildPropNames(UnionFind<T> types, String name) { Map<T, String> names = Maps.newHashMap(); for (Set<T> set : types.allEquivalenceClasses()) { checkState(!set.isEmpty()); String typeName = null; for (T type : set) { if (typeName == null || type.toString().compareTo(typeName) < 0) { typeName = type.toString(); } } String newName; if ("{...}".equals(typeName)) { newName = name; } else { newName = typeName.replaceAll("[^\\w$]", "_") + "$" + name; } for (T type : set) { names.put(type, newName); } } return names; } /** Returns a map from field name to types for which it will be renamed. */ Multimap<String, Collection<T>> getRenamedTypesForTesting() { Multimap<String, Collection<T>> ret = HashMultimap.create(); for (Map.Entry<String, Property> entry: properties.entrySet()) { Property prop = entry.getValue(); if (!prop.skipRenaming) { for (Collection<T> c : prop.getTypes().allEquivalenceClasses()) { if (!c.isEmpty() && !prop.typesToSkip.contains(c.iterator().next())) { ret.put(entry.getKey(), c); } } } } return ret

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS>; } /** Interface for providing the type information needed by this pass. */ private interface TypeSystem<T> { // TODO(user): add a getUniqueName(T type) method that is guaranteed // to be unique, performant and human-readable. /** Returns the top-most scope used by the type system (if any). */ StaticScope<T> getRootScope(); /** Returns the new scope started at the given function node. */ StaticScope<T> getFunctionScope(Node node); /** * Returns the type of the given node. * @param prop Only types with this property need to be returned. In general * with type tightening, this will require no special processing, but in * the case of an unknown JSType, we might need to add in the native * types since we don't track them, but only if they have the given * property. */ T getType(StaticScope<T> scope, Node node, String prop); /** * Returns true if a field reference on this type will invalidiate all * references to that field as candidates for renaming. This is true if the * type is unknown or all-inclusive, as variables with such a type could be * references to any object. */ boolean isInvalidatingType(T type); /** * Informs the given type system that a type is invalidating due to a type * mismatch found during type checking. */ void addInvalidatingType(JSType type); /** * Returns a set of types that should be skipped given the given type. * This is necessary for interfaces when using JSTypes, as all super * interfaces must also be skipped. */ ImmutableSet<T> getTypesToSkipForType(T type); /** * Determines whether the given type is one whose properties should not be * considered for renaming. */ boolean isTypeToSkip(T type); /** Remove null and undefined from the options in the given type. */ T restrictByNotNullOrUndefined(T type); /** * Returns the alternatives if this is a type that represents multiple * types, and null if not. Union and interface types can correspond to * multiple other types. */ Iterable<T> getTypeAlternatives(T type); /** * Returns the type in the chain from the

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS> given type that contains the given * field or null if it is not found anywhere. */ T getTypeWithProperty(String field, T type); /** * Returns the type of the instance of which this is the prototype or null * if this is not a function prototype. */ T getInstanceFromPrototype(T type); /** * Records that this property could be referenced from any interface that * this type, or any type in its superclass chain, implements. */ void recordInterfaces(T type, T relatedType, DisambiguateProperties<T>.Property p); } /** Implementation of TypeSystem using JSTypes. */ private static class JSTypeSystem implements TypeSystem<JSType> { private final Set<JSType> invalidatingTypes; private JSTypeRegistry registry; public JSTypeSystem(AbstractCompiler compiler) { registry = compiler.getTypeRegistry(); invalidatingTypes = Sets.newHashSet( registry.getNativeType(JSTypeNative.ALL_TYPE), registry.getNativeType(JSTypeNative.NO_OBJECT_TYPE), registry.getNativeType(JSTypeNative.NO_TYPE), registry.getNativeType(JSTypeNative.FUNCTION_PROTOTYPE), registry.getNativeType(JSTypeNative.FUNCTION_INSTANCE_TYPE), registry.getNativeType(JSTypeNative.OBJECT_PROTOTYPE), registry.getNativeType(JSTypeNative.TOP_LEVEL_PROTOTYPE), registry.getNativeType(JSTypeNative.UNKNOWN_TYPE)); } @Override public void addInvalidatingType(JSType type) { checkState(!type.isUnionType()); invalidatingTypes.add(type); } @Override public StaticScope<JSType> getRootScope() { return null; } @Override public StaticScope<JSType> getFunctionScope(Node node) { return null; } @Override public JSType getType( StaticScope<JSType> scope, Node node, String prop) { if (node.getJSType() == null) { return registry.getNativeType(JSTypeNative.UNKNOWN_TYPE); } return node.getJSType(); } @Override public boolean isInvalidatingType(JSType type) { if (type == null || invalidatingTypes.contains(type) ||

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS> type.isUnknownType() /* unresolved types */) { return true; } ObjectType objType = ObjectType.cast(type); return objType != null && !objType.hasReferenceName(); } @Override public ImmutableSet<JSType> getTypesToSkipForType(JSType type) { type = type.restrictByNotNullOrUndefined(); if (type instanceof UnionType) { Set<JSType> types = Sets.newHashSet(type); for (JSType alt : ((UnionType) type).getAlternates()) { types.addAll(getTypesToSkipForTypeNonUnion(type)); } return ImmutableSet.copyOf(types); } return ImmutableSet.copyOf(getTypesToSkipForTypeNonUnion(type)); } private Set<JSType> getTypesToSkipForTypeNonUnion(JSType type) { Set<JSType> types = Sets.newHashSet(); JSType skipType = type; while (skipType != null) { types.add(skipType); ObjectType objSkipType = skipType.toObjectType(); if (objSkipType != null) { skipType = objSkipType.getImplicitPrototype(); } else { break; } } return types; } @Override public boolean isTypeToSkip(JSType type) { return type.isEnumType() || (type.autoboxesTo() != null); } @Override public JSType restrictByNotNullOrUndefined(JSType type) { return type.restrictByNotNullOrUndefined(); } @Override public Iterable<JSType> getTypeAlternatives(JSType type) { if (type.isUnionType()) { return ((UnionType) type).getAlternates(); } else { ObjectType objType = type.toObjectType(); if (objType != null && objType.getConstructor() != null && objType.getConstructor().isInterface()) { List<JSType> list = Lists.newArrayList(); for (FunctionType impl : registry.getDirectImplementors(objType)) { list.add(impl.getInstanceType()); } return list; } else { return null; } } } @Override public ObjectType getTypeWithProperty(String field, JSType type) { if (!(type instanceof ObjectType)) { if (

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS>type.autoboxesTo() != null) { type = type.autoboxesTo(); } else { return null; } } // Ignore the prototype itself at all times. if ("prototype".equals(field)) { return null; } // We look up the prototype chain to find the highest place (if any) that // this appears. This will make references to overriden properties look // like references to the initial property, so they are renamed alike. ObjectType foundType = null; ObjectType objType = ObjectType.cast(type); while (objType != null && objType.getImplicitPrototype() != objType) { if (objType.hasOwnProperty(field)) { foundType = objType; } objType = objType.getImplicitPrototype(); } // If the property does not exist on the referenced type but the original // type is an object type, see if any subtype has the property. if (foundType == null) { ObjectType maybeType = ObjectType.cast( registry.getGreatestSubtypeWithProperty(type, field)); // getGreatestSubtypeWithProperty does not guarantee that the property // is defined on the returned type, it just indicates that it might be, // so we have to double check. if (maybeType != null && maybeType.hasOwnProperty(field)) { foundType = maybeType; } } return foundType; } @Override public JSType getInstanceFromPrototype(JSType type) { if (type.isFunctionPrototypeType()) { FunctionPrototypeType prototype = (FunctionPrototypeType) type; FunctionType owner = prototype.getOwnerFunction(); if (owner.isConstructor() || owner.isInterface()) { return ((FunctionPrototypeType) type).getOwnerFunction() .getInstanceType(); } } return null; } @Override public void recordInterfaces(JSType type, JSType relatedType, DisambiguateProperties<JSType>.Property p) { ObjectType objType = ObjectType.cast(type); if (objType != null) { FunctionType constructor; if (objType instanceof FunctionType) { constructor = (FunctionType) objType; } else if (objType instanceof FunctionPrototypeType) { constructor = ((FunctionPrototypeType) objType).getOwnerFunction(); } else {

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS> constructor = objType.getConstructor(); } while (constructor != null) { for (ObjectType itype : constructor.getImplementedInterfaces()) { JSType top = getTypeWithProperty(p.name, itype); if (top != null) { p.addType(itype, top, relatedType); } else { recordInterfaces(itype, relatedType, p); } // If this interface invalidated this property, return now. if (p.skipRenaming) return; } if (constructor.isInterface() || constructor.isConstructor()) { constructor = constructor.getSuperClassConstructor(); } else { constructor = null; } } } } } /** Implementation of TypeSystem using concrete types. */ private static class ConcreteTypeSystem implements TypeSystem<ConcreteType> { private final TightenTypes tt; private int nextUniqueId; private CodingConvention codingConvention; private final Set<JSType> invalidatingTypes = Sets.newHashSet(); // An array of native types that are not tracked by type tightening, and // thus need to be added in if an unknown type is encountered. private static final JSTypeNative [] nativeTypes = new JSTypeNative[] { JSTypeNative.BOOLEAN_OBJECT_TYPE, JSTypeNative.NUMBER_OBJECT_TYPE, JSTypeNative.STRING_OBJECT_TYPE }; public ConcreteTypeSystem(TightenTypes tt, CodingConvention convention) { this.tt = tt; this.codingConvention = convention; } @Override public void addInvalidatingType(JSType type) { checkState(!type.isUnionType()); invalidatingTypes.add(type); } @Override public StaticScope<ConcreteType> getRootScope() { return tt.getTopScope(); } @Override public StaticScope<ConcreteType> getFunctionScope(Node decl) { ConcreteFunctionType func = tt.getConcreteFunction(decl); return (func != null) ? func.getScope() : (StaticScope<ConcreteType>) null; } @Override public ConcreteType getType( StaticScope<ConcreteType> scope, Node node, String prop) { if (scope != null) { ConcreteType c = tt.inferConcreteType( (TightenTypes.ConcreteScope) scope

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS>, node); return maybeAddAutoboxes(c, node, prop); } else { return null; } } /** * Add concrete types for autoboxing types if necessary. The concrete type * system does not track native types, like string, so add them if they are * present in the JSType for the node. */ private ConcreteType maybeAddAutoboxes( ConcreteType cType, Node node, String prop) { JSType jsType = node.getJSType(); if (jsType == null) { return cType; } else if (jsType.isUnknownType()) { for (JSTypeNative nativeType : nativeTypes) { ConcreteType concrete = tt.getConcreteInstance( tt.getTypeRegistry().getNativeObjectType(nativeType)); if (concrete != null && !concrete.getPropertyType(prop).isNone()) { cType = cType.unionWith(concrete); } } return cType; } return maybeAddAutoboxes(cType, jsType, prop); } private ConcreteType maybeAddAutoboxes( ConcreteType cType, JSType jsType, String prop) { jsType = jsType.restrictByNotNullOrUndefined(); if (jsType instanceof UnionType) { for (JSType alt : ((UnionType) jsType).getAlternates()) { return maybeAddAutoboxes(cType, alt, prop); } } if (jsType.autoboxesTo() != null) { JSType autoboxed = jsType.autoboxesTo(); return cType.unionWith(tt.getConcreteInstance((ObjectType) autoboxed)); } else if (jsType.unboxesTo() != null) { return cType.unionWith(tt.getConcreteInstance((ObjectType) jsType)); } return cType; } @Override public boolean isInvalidatingType(ConcreteType type) { // We will disallow types on functions so that 'prototype' is not renamed. // TODO(user): Support properties on functions as well. return (type == null) || type.isAll() || type.isFunction() || (type.isInstance() && invalidatingTypes.contains(type.toInstance().instanceType)); } @Override public ImmutableSet<ConcreteType> getTypesToSkip

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS>ForType(ConcreteType type) { return ImmutableSet.of(type); } @Override public boolean isTypeToSkip(ConcreteType type) { // Skip anonymous object literals and enum types. return type.isInstance() && !(type.toInstance().isFunctionPrototype() || type.toInstance().instanceType.isInstanceType()); } @Override public ConcreteType restrictByNotNullOrUndefined(ConcreteType type) { // These are not represented in concrete types. return type; } @Override public Iterable<ConcreteType> getTypeAlternatives(ConcreteType type) { if (type.isUnion()) { return ((ConcreteUnionType) type).getAlternatives(); } else { return null; } } @Override public ConcreteType getTypeWithProperty(String field, ConcreteType type) { if (type.isInstance()) { ConcreteInstanceType instanceType = (ConcreteInstanceType) type; return instanceType.getInstanceTypeWithProperty(field); } else if (type.isFunction()) { if ("prototype".equals(field) || codingConvention.isSuperClassReference(field)) { return type; } } else if (type.isNone()) { // If the receiver is none, then this code is never reached. We will // return a new fake type to ensure that this access is renamed // differently from any other, so it can be easily removed. return new ConcreteUniqueType(++nextUniqueId); } else if (type.isUnion()) { // If only one has the property, return that. for (ConcreteType t : ((ConcreteUnionType) type).getAlternatives()) { ConcreteType ret = getTypeWithProperty(field, t); if (ret != null) { return ret; } } } return null; } @Override public ConcreteType getInstanceFromPrototype(ConcreteType type) { if (type.isInstance()) { ConcreteInstanceType instanceType = (ConcreteInstanceType) type; if (instanceType.isFunctionPrototype()) { return instanceType.getConstructorType().getInstanceType(); } } return null; } @Override public void recordInterfaces(ConcreteType type, ConcreteType relatedType, DisambiguateProperties<ConcreteType>.Property p) { // No need to record interfaces when

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS> } super.add(n, context); } private String getTypeAnnotation(Node node) { JSType type = node.getJSType(); if (type instanceof FunctionType) { return getFunctionAnnotation(node); } else if (type != null && !type.isUnknownType() && !type.isEmptyType() && !type.isVoidType() && !type.isFunctionPrototypeType()) { return "/** @type {" + node.getJSType() + "} */\n"; } else { return ""; } } /** * @param fnNode A node for a function for which to generate a type annotation */ private String getFunctionAnnotation(Node fnNode) { Preconditions.checkState(fnNode.getType() == Token.FUNCTION); StringBuilder sb = new StringBuilder("/**\n"); JSType type = fnNode.getJSType(); if (type == null || type.isUnknownType()) { return ""; } FunctionType funType = (FunctionType) fnNode.getJSType(); // We need to use the child nodes of the function as the nodes for the // parameters of the function type do not have the real parameter names. // FUNCTION // NAME // LP // NAME param1 // NAME param2 if (fnNode != null) { Node paramNode = NodeUtil.getFnParameters(fnNode).getFirstChild(); // Param types for (Node n : funType.getParameters()) { // Bail out if the paramNode is not there. if (paramNode == null) { break; } sb.append(" * @param {" + getParameterNodeJSDocType(n) + "} "); sb.append(paramNode.getString()); sb.append("\n"); paramNode = paramNode.getNext(); } } // Return type JSType retType = funType.getReturnType(); if (retType != null && !retType.isUnknownType() && !retType.isEmptyType()) { sb.append(" * @return {" + retType + "}\n"); } // Constructor/interface if (funType.isConstructor() || funType.isInterface()) { FunctionType superConstructor = funType.getSuperClassConstructor(); if (superConstructor != null)

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS>Constructor() { return referencedType.isConstructor(); } @Override public boolean isNominalType() { return referencedType.isNominalType(); } @Override public boolean isInstanceType() { return referencedType.isInstanceType(); } @Override public boolean isInterface() { return referencedType.isInterface(); } @Override public boolean isOrdinaryFunction() { return referencedType.isOrdinaryFunction(); } @Override public TernaryValue testForEquality(JSType that) { return referencedType.testForEquality(that); } @Override public boolean isSubtype(JSType that) { return referencedType.isSubtype(that); } @Override public Iterable<ObjectType> getCtorImplementedInterfaces() { return referencedObjType == null ? Collections.<ObjectType>emptyList() : referencedObjType.getCtorImplementedInterfaces(); } @Override public boolean canAssignTo(JSType that) { return referencedType.canAssignTo(that); } @Override public boolean isEquivalentTo(JSType that) { if (this == that) { return true; } return referencedType.isEquivalentTo(that); } @Override public int hashCode() { return referencedType.hashCode(); } @Override public String toString() { return referencedType.toString(); } @Override public ObjectType getImplicitPrototype() { return referencedObjType == null ? null : referencedObjType.getImplicitPrototype(); } @Override boolean defineProperty(String propertyName, JSType type, boolean inferred, boolean inExterns, Node propertyNode) { return referencedObjType == null ? true : referencedObjType.defineProperty( propertyName, type, inferred, inExterns, propertyNode); } @Override public boolean isPropertyTypeDeclared(String propertyName) { return referencedObjType == null ? false : referencedObjType.isPropertyTypeDeclared(propertyName); } @Override public Node getPropertyNode(String propertyName) { return referencedObjType == null ? null : referencedObjType.getPropertyNode(propertyName); } @Override public boolean isPropertyTypeInferred(String propertyName) { return referencedObjType == null ? false : referencedObjType.isPropertyTypeInferred(propertyName); } @Override public boolean isPropertyInExterns(

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS> { // If a.b is not a constructor, then treat this as a method // of whatever type is on "a". return normalizeClassType(lValue.getFirstChild().getJSType()); } } else { // We have an assignment of the form "a = ...", so pull the // type off the "a". return normalizeClassType(lValue.getJSType()); } } } else if (NodeUtil.isFunctionDeclaration(n) || parent.getType() == Token.NAME) { return normalizeClassType(n.getJSType()); } return null; } /** * Normalize the type of a constructor, its instance, and its prototype * all down to the same type (the instance type). */ private JSType normalizeClassType(JSType type) { if (type == null || type.isUnknownType()) { return type; } else if (type.isConstructor()) { return ((FunctionType) type).getInstanceType(); } else if (type.isFunctionPrototypeType()) { FunctionType owner = ((FunctionPrototypeType) type).getOwnerFunction(); if (owner.isConstructor()) { return owner.getInstanceType(); } } return type; } public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) { return true; } public void visit(NodeTraversal t, Node n, Node parent) { switch (n.getType()) { case Token.NAME: checkNameDeprecation(t, n, parent); checkNameVisibility(t, n, parent); break; case Token.GETPROP: checkPropertyDeprecation(t, n, parent); checkPropertyVisibility(t, n, parent); checkConstantProperty(t, n); break; case Token.NEW: checkConstructorDeprecation(t, n, parent); break; } } /** * Checks the given NEW node to ensure that access restrictions are obeyed. */ private void checkConstructorDeprecation(NodeTraversal t, Node n, Node parent) { JSType type = n.getJSType(); if (type != null) { String deprecationInfo = getTypeDeprecationInfo(type); if (deprecationInfo != null && shouldEmitDeprecationWarning(t, n, parent)) { if

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS> (!deprecationInfo.isEmpty()) { compiler.report( t.makeError(n, DEPRECATED_CLASS_REASON, type.toString(), deprecationInfo)); } else { compiler.report( t.makeError(n, DEPRECATED_CLASS, type.toString())); } } } } /** * Checks the given NAME node to ensure that access restrictions are obeyed. */ private void checkNameDeprecation(NodeTraversal t, Node n, Node parent) { // Don't bother checking definitions or constructors. if (parent.getType() == Token.FUNCTION || parent.getType() == Token.VAR || parent.getType() == Token.NEW) { return; } Scope.Var var = t.getScope().getVar(n.getString()); JSDocInfo docInfo = var == null ? null : var.getJSDocInfo(); if (docInfo != null && docInfo.isDeprecated() && shouldEmitDeprecationWarning(t, n, parent)) { if (docInfo.getDeprecationReason() != null) { compiler.report( t.makeError(n, DEPRECATED_NAME_REASON, n.getString(), docInfo.getDeprecationReason())); } else { compiler.report( t.makeError(n, DEPRECATED_NAME, n.getString())); } } } /** * Checks the given GETPROP node to ensure that access restrictions are * obeyed. */ private void checkPropertyDeprecation(NodeTraversal t, Node n, Node parent) { // Don't bother checking constructors. if (parent.getType() == Token.NEW) { return; } ObjectType objectType = ObjectType.cast(dereference(n.getFirstChild().getJSType())); String propertyName = n.getLastChild().getString(); if (objectType != null) { String deprecationInfo = getPropertyDeprecationInfo(objectType, propertyName); if (deprecationInfo != null && shouldEmitDeprecationWarning(t, n, parent)) { if (!deprecationInfo.isEmpty()) { compiler.report( t.makeError(n, DEPRECATED_PROP_REASON, propertyName, validator.getReadableJSTypeName(n.getFirstChild(), true), deprecationInfo)); } else { compiler.report(

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS>) || // Case #2 (getTypeDeprecationInfo(t.getScope().getTypeOfThis()) != null) || // Case #3 (scopeRootParent != null && scopeRootParent.getType() == Token.ASSIGN && getTypeDeprecationInfo( getClassOfMethod(scopeRoot, scopeRootParent)) != null); } /** * Returns whether this is a function node annotated as deprecated. */ private static boolean isDeprecatedFunction(Node n, Node parent) { if (n.getType() == Token.FUNCTION) { JSType type = n.getJSType(); if (type != null) { return getTypeDeprecationInfo(type) != null; } } return false; } /** * Returns the deprecation reason for the type if it is marked * as being deprecated. Returns empty string if the type is deprecated * but no reason was given. Returns null if the type is not deprecated. */ private static String getTypeDeprecationInfo(JSType type) { if (type == null) { return null; } JSDocInfo info = type.getJSDocInfo(); if (info != null && info.isDeprecated()) { if (info.getDeprecationReason() != null) { return info.getDeprecationReason(); } return ""; } ObjectType objType = ObjectType.cast(type); if (objType != null) { ObjectType implicitProto = objType.getImplicitPrototype(); if (implicitProto != null) { return getTypeDeprecationInfo(implicitProto); } } return null; } /** * Returns the deprecation reason for the property if it is marked * as being deprecated. Returns empty string if the property is deprecated * but no reason was given. Returns null if the property is not deprecated. */ private static String getPropertyDeprecationInfo(ObjectType type, String prop) { JSDocInfo info = type.getOwnPropertyJSDocInfo(prop); if (info != null && info.isDeprecated()) { if (info.getDeprecationReason() != null) { return info.getDeprecationReason(); } return ""; } ObjectType implicitProto = type.getImplicitPrototype(); if (implicitProto != null) { return getPropertyDeprecationInfo(implicitProto, prop);

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS> } return null; } /** * Dereference a type, autoboxing it and filtering out null. */ private static JSType dereference(JSType type) { return type == null ? null : type.dereference(); } }

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS>JSTypeRegistry registry) { this.registry = registry; } /** * Add parameters of the given type to the end of the param list. * @return False if this is called after optional params are added. */ public boolean addRequiredParams(JSType ...types) { if (hasOptionalOrVarArgs()) { return false; } for (JSType type : types) { newParameter(type); } return true; } /** * Add optional parameters of the given type to the end of the param list. * @param types Types for each optional parameter. The builder will make them * undefineable. * @return False if this is called after var args are added. */ public boolean addOptionalParams(JSType ...types) { if (hasVarArgs()) { return false; } for (JSType type : types) { newParameter(registry.createOptionalType(type)).setOptionalArg(true); } return true; } /** * Add variable arguments to the end of the parameter list. * @return False if this is called after var args are added. */ public boolean addVarArgs(JSType type) { if (hasVarArgs()) { return false; } // There are two types of variable argument functions: // 1) Programmer-defined var args // 2) Native bottom types that can accept any argument. // For the first one, "undefined" is a valid value for all arguments. // For the second, we do not want to cast it up to undefined. if (!type.isEmptyType()) { type = registry.createOptionalType(type); } newParameter(type).setVarArgs(true); return true; } /** * Copies the parameter specification from the given node. */ public Node newParameterFromNode(Node n) { Node newParam = newParameter(n.getJSType()); newParam.setVarArgs(n.isVarArgs()); newParam.setOptionalArg(n.isOptionalArg()); return newParam; } // Add a parameter to the list with the given type. private Node newParameter(JSType type) { Node paramNode = Node.newString(Token.NAME, ""); paramNode

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS>.setJSType(type); root.addChildToBack(paramNode); return paramNode; } public Node build() { return root; } private boolean hasOptionalOrVarArgs() { Node lastChild = root.getLastChild(); return lastChild != null && (lastChild.isOptionalArg() || lastChild.isVarArgs()); } public boolean hasVarArgs() { Node lastChild = root.getLastChild(); return lastChild != null && lastChild.isVarArgs(); } }

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS>Node callNode); /** * Returns true if passed a string referring to the superclass. The string * will usually be from the string node at the right of a GETPROP, e.g. * this.superClass_. */ public boolean isSuperClassReference(String propertyName); /** * Convenience method for determining provided dependencies amongst different * js scripts. */ public String extractClassNameIfProvide(Node node, Node parent); /** * Convenience method for determining required dependencies amongst different * js scripts. */ public String extractClassNameIfRequire(Node node, Node parent); /** * Function name used when exporting properties. * Signature: fn(object, publicName, symbol). * @return function name. */ public String getExportPropertyFunction(); /** * Function name used when exporting symbols. * Signature: fn(publicPath, object). * @return function name. */ public String getExportSymbolFunction(); /** * Checks if the given CALL node is forward-declaring any types, * and returns the name of the types if it is. */ public List<String> identifyTypeDeclarationCall(Node n); /** * Checks if the given ASSIGN node is a typedef, and returns the * name of the type if it is. */ public String identifyTypeDefAssign(Node n); /** * In many JS libraries, the function that produces inheritance also * adds properties to the superclass and/or subclass. */ public void applySubclassRelationship(FunctionType parentCtor, FunctionType childCtor, SubclassType type); /** * Function name for abstract methods. An abstract method can be assigned to * an interface method instead of an function expression in order to avoid * linter warnings produced by assigning a function without a return value * where a return value is expected. * @return function name. */ public String getAbstractMethodName(); /** * Checks if the given method defines a singleton getter, and if it does, * returns the name of the class with the singleton getter. By default, always * returns null. Meant to be overridden by subclasses. * * @param callNode A CALL node. */ public String getSingletonGetterClassName(Node callNode); /** * In many JS libraries, the function that adds a singleton getter to a class

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS> * adds properties to the class. */ public void applySingletonGetter(FunctionType functionType, FunctionType getterType, ObjectType objectType); public DelegateRelationship getDelegateRelationship(Node callNode); /** * In many JS libraries, the function that creates a delegate relationship * also adds properties to the delegator and delegate base. */ public void applyDelegateRelationship( ObjectType delegateSuperclass, ObjectType delegateBase, ObjectType delegator, FunctionType delegateProxy, FunctionType findDelegate); /** * @return the name of the delegate superclass. */ public String getDelegateSuperclassName(); /** * Defines the delegate proxy prototype properties. Their types depend on * properties of the delegate base methods. * * @param delegateProxyPrototypes List of delegate proxy prototypes. */ public void defineDelegateProxyPrototypeProperties( JSTypeRegistry registry, Scope scope, List<ObjectType> delegateProxyPrototypes); /** * Gets the name of the global object. */ public String getGlobalObject(); /** * Whether this CALL function is testing for the existence of a property. */ public boolean isPropertyTestFunction(Node call); /** * Checks if the given method performs a object literal cast, and if it does, * returns information on the cast. By default, always returns null. Meant * to be overridden by subclasses. * * @param t The node traversal. * @param callNode A CALL node. */ public ObjectLiteralCast getObjectLiteralCast(NodeTraversal t, Node callNode); /** * Returns the set of AssertionFunction. */ public Collection<AssertionFunctionSpec> getAssertionFunctions(); static enum SubclassType { INHERITS, MIXIN } static class SubclassRelationship { final SubclassType type; final String subclassName; final String superclassName; SubclassRelationship(SubclassType type, Node subclassNode, Node superclassNode) { this.type = type; this.subclassName = subclassNode.getQualifiedName(); this.superclassName = superclassNode.getQualifiedName(); } } /** * Delegates provides a mechanism and structure for identifying where classes * can call out to optional code to augment their functionality. The optional * code is isolated from the base code through the use of a subclass in the * optional code derived

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS> // For example: "return foo;" append(" "); } append(newcode); } void appendOp(String op, boolean binOp) { append(op); } void addOp(String op, boolean binOp) { maybeEndStatement(); char first = op.charAt(0); char prev = getLastChar(); if ((first == '+' || first == '-') && prev == first) { // This is not pretty printing. This is to prevent misparsing of // things like "x + ++y" or "x++ + ++y" append(" "); } else if (Character.isLetter(first) && isWordChar(prev)) { // Make sure there is a space after e.g. instanceof , typeof append(" "); } else if (prev == '-' && first == '>') { // Make sure that we don't emit --> append(" "); } // Allow formating around the operator. appendOp(op, binOp); // Line breaking after an operator is always safe. Line breaking before an // operator on the other hand is not. We only line break after a bin op // because it looks strange. if (binOp) { maybeCutLine(); } } void addNumber(double x) { // This is not pretty printing. This is to prevent misparsing of x- -4 as // x--4 (which is a syntax error). char prev = getLastChar(); if (x < 0 && prev == '-') { add(" "); } if ((long) x == x) { long value = (long) x; long mantissa = value; int exp = 0; if (Math.abs(x) >= 100) { while (mantissa / 10 * Math.pow(10, exp + 1) == value) { mantissa /= 10; exp++; } } if (exp > 2) { add(Long.toString(mantissa) + "E" + Integer.toString(exp)); } else { add(Long.toString(value)); } } else { add(String.valueOf(x)); } } static boolean isWordChar(char ch) { return (ch ==

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS> { boolean canAssign = true; for (JSType t : alternates) { if (t.isUnknownType()) { return true; } canAssign &= t.canAssignTo(that); } return canAssign; } @Override public boolean canBeCalled() { for (JSType t : alternates) { if (!t.canBeCalled()) { return false; } } return true; } @Override public JSType restrictByNotNullOrUndefined() { UnionTypeBuilder restricted = new UnionTypeBuilder(registry); for (JSType t : alternates) { restricted.addAlternate(t.restrictByNotNullOrUndefined()); } return restricted.build(); } @Override public TernaryValue testForEquality(JSType that) { TernaryValue result = null; for (JSType t : alternates) { TernaryValue test = t.testForEquality(that); if (result == null) { result = test; } else if (!result.equals(test)) { return UNKNOWN; } } return result; } /** * This predicate determines whether objects of this type can have the * {@code null} value, and therefore can appear in contexts where * {@code null} is expected. * * @return {@code true} for everything but {@code Number} and * {@code Boolean} types. */ @Override public boolean isNullable() { for (JSType t : alternates) { if (t.isNullable()) { return true; } } return false; } @Override public boolean isUnknownType() { for (JSType t : alternates) { if (t.isUnknownType()) { return true; } } return false; } @Override public JSType getLeastSupertype(JSType that) { if (!that.isUnknownType() && !that.isUnionType()) { for (JSType alternate : alternates) { if (!alternate.isUnknownType() && that.isSubtype(alternate)) { return this; } } } return getLeastSupertype(this, that); } JSType meet(JSType that) { UnionTypeBuilder builder

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS> = new UnionTypeBuilder(registry); for (JSType alternate : alternates) { if (alternate.isSubtype(that)) { builder.addAlternate(alternate); } } if (that instanceof UnionType) { for (JSType otherAlternate : ((UnionType) that).alternates) { if (otherAlternate.isSubtype(this)) { builder.addAlternate(otherAlternate); } } } else if (that.isSubtype(this)) { builder.addAlternate(that); } JSType result = builder.build(); if (!result.isNoType()) { return result; } else if (this.isObject() && that.isObject()) { return getNativeType(JSTypeNative.NO_OBJECT_TYPE); } else { return getNativeType(JSTypeNative.NO_TYPE); } } /** * Two union types are equal if they have the same number of alternates * and all alternates are equal. */ @Override public boolean isEquivalentTo(JSType object) { if (object instanceof UnionType) { UnionType that = (UnionType) object; if (alternates.size() != that.alternates.size()) { return false; } for (JSType alternate : that.alternates) { if (!hasAlternate(alternate)) { return false; } } return true; } else { return false; } } private boolean hasAlternate(JSType type) { for (JSType alternate : alternates) { if (alternate.isEquivalentTo(type)) { return true; } } return false; } @Override public int hashCode() { return this.hashcode; } @Override public boolean isUnionType() { return true; } @Override public boolean isObject() { for (JSType alternate : alternates) { if (!alternate.isObject()) { return false; } } return true; } /** * A {@link UnionType} contains a given type (alternate) iff the member * vector contains it. * * @param alternate The alternate which might be in this union. * * @return {@code true} if the alternate is in the union */

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS> public boolean contains(JSType type) { for (JSType alt : alternates) { if (alt.isEquivalentTo(type)) { return true; } } return false; } /** * Returns a more restricted union type than {@code this} one, in which all * subtypes of {@code type} have been removed.<p> * * Examples: * <ul> * <li>{@code (number,string)} restricted by {@code number} is * {@code string}</li> * <li>{@code (null, EvalError, URIError)} restricted by * {@code Error} is {@code null}</li> * </ul> * * @param type the supertype of the types to remove from this union type */ public JSType getRestrictedUnion(JSType type) { UnionTypeBuilder restricted = new UnionTypeBuilder(registry); for (JSType t : alternates) { if (t.isUnknownType() || !t.isSubtype(type)) { restricted.addAlternate(t); } } return restricted.build(); } @Override public String toString() { StringBuilder result = new StringBuilder(); boolean firstAlternate = true; result.append("("); SortedSet<JSType> sorted = new TreeSet<JSType>(ALPHA); sorted.addAll(alternates); for (JSType t : sorted) { if (!firstAlternate) { result.append("|"); } result.append(t.toString()); firstAlternate = false; } result.append(")"); return result.toString(); } @Override public boolean isSubtype(JSType that) { // unknown if (that.isUnknownType()) { return true; } // all type if (that.isAllType()) { return true; } for (JSType element : alternates) { if (!element.isSubtype(that)) { return false; } } return true; } @Override public JSType getRestrictedTypeGivenToBooleanOutcome(boolean outcome) { // gather elements after restriction UnionTypeBuilder restricted = new UnionTypeBuilder(registry); for (JSType element : alternates) { restricted.addAlternate( element.getRestricted

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS>TypeNative.NO_TYPE); } @Override public boolean hasProperty(String propertyName) { // has all properties, since it is any object return true; } @Override boolean defineProperty(String propertyName, JSType type, boolean inferred, boolean inExterns, Node propertyNode) { // nothing, all properties are defined return true; } @Override public JSDocInfo getOwnPropertyJSDocInfo(String propertyName) { return null; } @Override public void setPropertyJSDocInfo(String propertyName, JSDocInfo info, boolean inExterns) { // Do nothing, specific properties do not have JSDocInfo. } @Override public boolean isPropertyTypeInferred(String propertyName) { return false; } @Override public <T> T visit(Visitor<T> visitor) { return visitor.caseNoObjectType(); } @Override public String toString() { return "NoObject"; } @Override public FunctionType getConstructor() { return null; } @Override JSType resolveInternal(ErrorReporter t, StaticScope<JSType> scope) { return this; } }

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS> int lineNumber, String lineSource, int columnNumber) { return new EcmaError(error, message, sourceName, lineNumber, lineSource, columnNumber); } public static EcmaError typeError(String message) { return constructError("TypeError", message); } public static EcmaError typeError0(String messageId) { String msg = getMessage0(messageId); return typeError(msg); } public static EcmaError typeError1(String messageId, String arg1) { String msg = getMessage1(messageId, arg1); return typeError(msg); } public static EcmaError typeError2(String messageId, String arg1, String arg2) { String msg = getMessage2(messageId, arg1, arg2); return typeError(msg); } public static EcmaError typeError3(String messageId, String arg1, String arg2, String arg3) { String msg = getMessage3(messageId, arg1, arg2, arg3); return typeError(msg); } public static RuntimeException undefReadError(Object object, Object id) { String idStr = (id == null) ? "null" : id.toString(); return typeError2("msg.undef.prop.read", toString(object), idStr); } public static RuntimeException undefCallError(Object object, Object id) { String idStr = (id == null) ? "null" : id.toString(); return typeError2("msg.undef.method.call", toString(object), idStr); } public static RuntimeException undefWriteError(Object object, Object id, Object value) { String idStr = (id == null) ? "null" : id.toString(); String valueStr = toString(value); return typeError3("msg.undef.prop.write", toString(object), idStr, valueStr); } public static RuntimeException notFunctionError(Object value) { return notFunctionError(value, value); } public static RuntimeException notFunctionError(Object value, Object messageHelper) { // XXX Use value for better error reporting String msg = (messageHelper == null) ? "null" : messageHelper.toString(); return

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS> typeError2("msg.isnt.function", msg, value == null ? "null" : value.getClass().getName()); } static int lastIndexResult(Context cx) { return cx.scratchIndex; } public static void storeUint32Result(Context cx, long value) { if ((value >>> 32) != 0) throw new IllegalArgumentException(); cx.scratchUint32 = value; } public static long lastUint32Result(Context cx) { long value = cx.scratchUint32; if ((value >>> 32) != 0) throw new IllegalStateException(); return value; } static String makeUrlForGeneratedScript (boolean isEval, String masterScriptUrl, int masterScriptLine) { if (isEval) { return masterScriptUrl+'#'+masterScriptLine+"(eval)"; } else { return masterScriptUrl+'#'+masterScriptLine+"(Function)"; } } static boolean isGeneratedScript(String sourceUrl) { // ALERT: this may clash with a valid URL containing (eval) or // (Function) return sourceUrl.indexOf("(eval)") >= 0 || sourceUrl.indexOf("(Function)") >= 0; } public static final Object[] emptyArgs = new Object[0]; public static final String[] emptyStrings = new String[0]; }

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS>); } @Override public boolean isPrivate(String name) { return false; } @Override public SubclassRelationship getClassesDefinedByCall(Node callNode) { return null; } @Override public boolean isSuperClassReference(String propertyName) { return false; } @Override public String extractClassNameIfProvide(Node node, Node parent) { String message = "only implemented in GoogleCodingConvention"; throw new UnsupportedOperationException(message); } @Override public String extractClassNameIfRequire(Node node, Node parent) { String message = "only implemented in GoogleCodingConvention"; throw new UnsupportedOperationException(message); } @Override public String getExportPropertyFunction() { return null; } @Override public String getExportSymbolFunction() { return null; } @Override public List<String> identifyTypeDeclarationCall(Node n) { return null; } @Override public String identifyTypeDefAssign(Node n) { return null; } @Override public void applySubclassRelationship(FunctionType parentCtor, FunctionType childCtor, SubclassType type) { // do nothing } @Override public String getAbstractMethodName() { return null; } @Override public String getSingletonGetterClassName(Node callNode) { return null; } @Override public void applySingletonGetter(FunctionType functionType, FunctionType getterType, ObjectType objectType) { // do nothing. } @Override public DelegateRelationship getDelegateRelationship(Node callNode) { return null; } @Override public void applyDelegateRelationship( ObjectType delegateSuperclass, ObjectType delegateBase, ObjectType delegator, FunctionType delegateProxy, FunctionType findDelegate) { // do nothing. } @Override public String getDelegateSuperclassName() { return null; } @Override public void defineDelegateProxyPrototypeProperties( JSTypeRegistry registry, Scope scope, List<ObjectType> delegateProxyPrototypes) { // do nothing. } @Override public String getGlobalObject() { return "window"; } @Override public boolean isPropertyTestFunction(Node call) { return false; } @Override public ObjectLiteralCast getObjectLiteralCast(NodeTraversal t, Node callNode) {

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS>, n2)) { connect(n1, edge, n2); } } /** * Gets a node from the graph given a value. New nodes are created if that * value has not been assigned a graph node. Values equality are compared * using <code>Object.equals</code>. * * @param value The node's value. * @return The corresponding node in the graph. */ public abstract GraphNode<N, E> createNode(N value); /** Gets an immutable list of all nodes. */ public abstract Collection<GraphNode<N, E>> getNodes(); /** Gets an immutable list of all edges. */ public abstract List<GraphEdge<N, E>> getEdges(); /** * Gets the degree of a node. * * @param value The node's value. * @return The degree of the node. */ public abstract int getNodeDegree(N value); public int getWeight(N value) { return getNodeDegree(value); } /** * Gets the neighboring nodes. * * @param value The node's value. * @return A list of neighboring nodes. */ public abstract List<GraphNode<N, E>> getNeighborNodes(N value); public abstract Iterator<GraphNode<N, E>> getNeighborNodesIterator(N value); /** * Retrieves an edge from the graph. * * @param n1 Node one. * @param n2 Node two. * @return The list of edges between those two values in the graph. */ public abstract List<GraphEdge<N, E>> getEdges(N n1, N n2); /** * Retrieves any edge from the graph. * * @param n1 Node one. * @param n2 Node two. * @return The first edges between those two values in the graph. null if * there are none. */ public abstract GraphEdge<N, E> getFirstEdge(N n1, N n2); /** * Checks whether the node exists in the graph ({@link #createNode(Object)} * has been called with that value). * * @param n Node. * @return <code>true</code> if it exist. */ public final boolean hasNode(

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS>AnnotationStack == null) { edgeAnnotationStack = Lists.newLinkedList(); } pushAnnotations(edgeAnnotationStack, getEdges()); } /** * Restores edges' annotation values to state before last * {@link #pushEdgeAnnotations()}. */ public final void popEdgeAnnotations() { Preconditions.checkNotNull(edgeAnnotationStack, "Popping edge annotations without pushing."); popAnnotations(edgeAnnotationStack); } /** * A generic edge. * * @param <N> Value type that the graph node stores. * @param <E> Value type that the graph edge stores. */ public interface GraphEdge<N, E> extends Annotatable { /** * Retrieves the edge's value. * * @return The value. */ E getValue(); GraphNode<N, E> getNodeA(); GraphNode<N, E> getNodeB(); } /** * A simple implementation of SubGraph that calculates adjacency by iterating * over a node's neighbors. */ class SimpleSubGraph<N, E> implements SubGraph<N, E> { private Graph<N, E> graph; private List<GraphNode<N, E>> nodes = Lists.newArrayList(); SimpleSubGraph(Graph<N, E> graph) { this.graph = graph; } public boolean isIndependentOf(N value) { GraphNode<N, E> node = graph.getNode(value); for (GraphNode<N, E> n : nodes) { if (graph.getNeighborNodes(n.getValue()).contains(node)) { return false; } } return true; } public void addNode(N value) { nodes.add(graph.getNodeOrFail(value)); } } /** * Pushes a new list on stack and stores nodes annotations in the new list. * Clears objects' annotations as well. */ private static void pushAnnotations( Deque<GraphAnnotationState> stack, Collection<? extends Annotatable> haveAnnotations) { stack.push(new GraphAnnotationState(haveAnnotations.size())); for (Annotatable h : haveAnnotations) { stack.peek().add(new AnnotationState(h, h.getAnnotation())); h.setAnnotation(null); } } /** *

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS> { // Only report error when there are some line number informations. // There are synthetic nodes with no line number informations, nodes // introduce by other passes (although not likely since this pass should // be executed early) or some rhino bug. if (n.getLineno() != -1 && // Allow spurious semi-colons and spurious breaks. n.getType() != Token.EMPTY && n.getType() != Token.BREAK) { compiler.report(t.makeError(n, level, UNREACHABLE_CODE)); // From now on, we are going to assume the user fixed the error and not // give more warning related to code section reachable from this node. new GraphReachability<Node, ControlFlowGraph.Branch>( t.getControlFlowGraph()).recompute(n); // Saves time by not traversing children. return false; } } return true; } private void initScope(ControlFlowGraph<Node> controlFlowGraph) { new GraphReachability<Node, ControlFlowGraph.Branch>( controlFlowGraph, new ReachablePredicate()).compute( controlFlowGraph.getEntry().getValue()); } @Override public void exitScope(NodeTraversal t) { } @Override public void visit(NodeTraversal t, Node n, Node parent) { } private final class ReachablePredicate implements Predicate<EdgeTuple<Node, ControlFlowGraph.Branch>> { @Override public boolean apply(EdgeTuple<Node, Branch> input) { Branch branch = input.edge; if (!branch.isConditional()) { return true; } Node predecessor = input.sourceNode; Node condition = NodeUtil.getConditionExpression(predecessor); // TODO(user): Handle more complicated expression like true == true, // etc.... if (condition != null) { TernaryValue val = NodeUtil.getImpureBooleanValue(condition); if (val != TernaryValue.UNKNOWN) { return val.toBoolean(true) == (branch == Branch.ON_TRUE); } } return true; } } }

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS> {@link #FALSE} only if all replacements of {@link #UNKNOWN} in this * expression yield the same result. Therefore, the ternary logic coincides * with typical boolean logic if the {@link #UNKNOWN} value is not * present in an expression.</p> * * @see <a href="http://en.wikipedia.org/wiki/Ternary_logic">Ternary Logic</a> */ public enum TernaryValue { /** * {@code false} */ FALSE { @Override public TernaryValue and(TernaryValue that) { return FALSE; } @Override public TernaryValue not() { return TRUE; } @Override public TernaryValue or(TernaryValue that) { return that; } @Override public TernaryValue xor(TernaryValue that) { return that; } @Override public boolean toBoolean(boolean unknown) { return false; } @Override public String toString() { return "false"; } }, /** * {@code true} */ TRUE { @Override public TernaryValue and(TernaryValue that) { return that; } @Override public TernaryValue not() { return FALSE; } @Override public TernaryValue or(TernaryValue that) { return TRUE; } @Override public TernaryValue xor(TernaryValue that) { return that.not(); } @Override public boolean toBoolean(boolean unknown) { return true; } @Override public String toString() { return "true"; } }, /** * {@code unknown}, it represents lack of knowledge about whether this value * is {@code true} or {@code false}. */ UNKNOWN { @Override public TernaryValue and(TernaryValue that) { return (FALSE.equals(that)) ? FALSE : UNKNOWN; } @Override public TernaryValue not() { return UNKNOWN; } @Override public TernaryValue or(TernaryValue that) { return (TRUE.equals(that)) ? TRUE : UNKNOWN; } @Override public TernaryValue xor(TernaryValue that) { return UNKNOWN; } @Override public boolean to

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS>Boolean(boolean unknown) { return unknown; } @Override public String toString() { return "unknown"; } }; /** * Gets the {@code and} of {@code this} and {@code that}. */ public abstract TernaryValue and(TernaryValue that); /** * Gets the {@code not} of {@code this}. */ public abstract TernaryValue not(); /** * Gets the {@code or} of {@code this} and {@code that}. */ public abstract TernaryValue or(TernaryValue that); /** * Gets the {@code xor} of {@code this} and {@code that}. */ public abstract TernaryValue xor(TernaryValue that); /** * Converts {@code this} ternary value to boolean. The {@code #TRUE} and * {@code #FALSE} values are simply converted to {@code true} and * {@code false} respectively, whilst the {@link #UNKNOWN} is converted * to the specified {@code unknown} value. * * @param unknown the boolean value to which the {@link #UNKNOWN} value is * converted * @return <pre>return * this == TRUE ? true : * this == FALSE ? false : * unknown</pre> */ public abstract boolean toBoolean(boolean unknown); /** * Gets the TernaryValue for the given boolean. */ public static TernaryValue forBoolean(boolean val) { return val ? TernaryValue.TRUE : TernaryValue.FALSE; } }

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS>/* * Copyright 2004 The Closure Compiler Authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.javascript.jscomp.CheckLevel; import com.google.javascript.rhino.Node; import javax.annotation.Nullable; /** * Compile error description * */ public class JSError { /** A type of the error */ private final DiagnosticType type; /** Description of the error */ public final String description; /** Name of the source */ public final String sourceName; /** Node where the warning occurred. */ final Node node; /** Line number of the source */ public final int lineNumber; /** Level */ public final CheckLevel level; // character number private final int charno; // // JSError.make - static factory methods for creating JSError objects // // The general form of the arguments is // // [source location] [level] DiagnosticType [argument ...] // // This order echos a typical command line diagnostic. Source location // arguments are arranged to be sources of information in the order // file-line-column. // // If the level is not given, it is taken from the level of the // DiagnosticType. /** * Creates a JSError with no source information * * @param type The DiagnosticType * @param arguments Arguments to be incorporated into the message */ public static JSError make(DiagnosticType type, String... arguments) { return new JSError(null, null, -1, -1, type, null, arguments); } /** * Creates a JSError at a given source location * * @

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS>param sourceName The source file name * @param lineno Line number with source file, or -1 if unknown * @param charno Column number within line, or -1 for whole line. * @param type The DiagnosticType * @param arguments Arguments to be incorporated into the message */ public static JSError make(String sourceName, int lineno, int charno, DiagnosticType type, String... arguments) { return new JSError(sourceName, null, lineno, charno, type, null, arguments); } /** * Creates a JSError at a given source location * * @param sourceName The source file name * @param lineno Line number with source file, or -1 if unknown * @param charno Column number within line, or -1 for whole line. * @param type The DiagnosticType * @param arguments Arguments to be incorporated into the message */ public static JSError make(String sourceName, int lineno, int charno, CheckLevel level, DiagnosticType type, String... arguments) { return new JSError( sourceName, null, lineno, charno, type, level, arguments); } /** * Creates a JSError from a file and Node position. * * @param sourceName The source file name * @param n Determines the line and char position within the source file name * @param type The DiagnosticType * @param arguments Arguments to be incorporated into the message */ public static JSError make(String sourceName, Node n, DiagnosticType type, String... arguments) { return new JSError(sourceName, n, type, arguments); } /** * Creates a JSError from a file and Node position. * * @param sourceName The source file name * @param n Determines the line and char position within the source file name * @param type The DiagnosticType * @param arguments Arguments to be incorporated into the message */ public static JSError make(String sourceName, Node n, CheckLevel level, DiagnosticType type, String... arguments) { return new JSError(sourceName, n, n.getLineno(), n.getCharno(), type, level, arguments); } // // JSError constructors // /** * Creates a JSError at a CheckLevel for a source

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS> file location. * Private to avoid any entanglement with code outside of the compiler. */ private JSError( String sourceName, @Nullable Node node, int lineno, int charno, DiagnosticType type, CheckLevel level, String... arguments) { this.type = type; this.node = node; this.description = type.format.format(arguments); this.lineNumber = lineno; this.charno = charno; this.sourceName = sourceName; this.level = level == null ? type.level : level; } /** * Creates a JSError for a source file location. Private to avoid * any entanglement with code outside of the compiler. */ private JSError(String sourceName, @Nullable Node node, DiagnosticType type, String... arguments) { this(sourceName, node, (node != null) ? node.getLineno() : -1, (node != null) ? node.getCharno() : -1, type, null, arguments); } public DiagnosticType getType() { return type; } /** * Format a message at the given level. * * @return the formatted message or {@code null} */ public String format(CheckLevel level, MessageFormatter formatter) { switch (level) { case ERROR: return formatter.formatError(this); case WARNING: return formatter.formatWarning(this); default: return null; } } @Override public String toString() { // TODO(user): remove custom toString. return type.key + ". " + description + " at " + (sourceName != null && sourceName.length() > 0 ? sourceName : "(unknown source)") + " line " + (lineNumber != -1 ? String.valueOf(lineNumber) : "(unknown line)") + " : " + (charno != -1 ? String.valueOf(charno) : "(unknown column)"); } /** * Get the character number. */ public int getCharno() { return charno; } @Override public boolean equals(Object o) { // Generated by Intellij IDEA if (this == o) { return true; } if (o == null || getClass() !=

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS> o.getClass()) { return false; } JSError jsError = (JSError) o; if (charno != jsError.charno) { return false; } if (lineNumber != jsError.lineNumber) { return false; } if (!description.equals(jsError.description)) { return false; } if (level != jsError.level) { return false; } if (sourceName != null ? !sourceName.equals(jsError.sourceName) : jsError.sourceName != null) { return false; } if (!type.equals(jsError.type)) { return false; } return true; } @Override public int hashCode() { // Generated by Intellij IDEA int result = type.hashCode(); result = 31 * result + description.hashCode(); result = 31 * result + (sourceName != null ? sourceName.hashCode() : 0); result = 31 * result + lineNumber; result = 31 * result + level.hashCode(); result = 31 * result + charno; return result; } }

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS>/* * Copyright 2010 The Closure Compiler Authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.collect.Maps; import com.google.javascript.rhino.JSDocInfo; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import java.util.Map; /** * Filters warnings based on in-code {@code @suppress} annotations. * @author nicksantos@google.com (Nick Santos) */ class SuppressDocWarningsGuard extends WarningsGuard { /** Warnings guards for each suppressable warnings group, indexed by name. */ private final Map<String, DiagnosticGroupWarningsGuard> suppressors = Maps.newHashMap(); /** * The suppressable groups, indexed by name. */ SuppressDocWarningsGuard(Map<String, DiagnosticGroup> suppressableGroups) { for (Map.Entry<String, DiagnosticGroup> entry : suppressableGroups.entrySet()) { suppressors.put( entry.getKey(), new DiagnosticGroupWarningsGuard( entry.getValue(), CheckLevel.OFF)); } } @Override public CheckLevel level(JSError error) { Node node = error.node; if (node != null) { for (Node current = node; current != null; current = current.getParent()) { int type = current.getType(); JSDocInfo info = null; // We only care about function annotations at the FUNCTION and SCRIPT // level. Otherwise, the @suppress annotation has an implicit // dependency on the exact structure of our AST, and that seems like // a bad idea

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS>. if (type == Token.FUNCTION) { info = NodeUtil.getFunctionInfo(current); } else if (type == Token.SCRIPT) { info = current.getJSDocInfo(); } if (info != null) { for (String suppressor : info.getSuppressions()) { WarningsGuard guard = suppressors.get(suppressor); // Some @suppress tags are for other tools, and // may not have a warnings guard. if (guard != null) { CheckLevel newLevel = guard.level(error); if (newLevel != null) { return newLevel; } } } } } } return null; } @Override public int getPriority() { // Happens after path-based filtering, but before other times // of filtering. return WarningsGuard.Priority.SUPPRESS_DOC.value; } }

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS> abstract T processSwitchStatement(SwitchStatement statementNode); abstract T processThrowStatement(ThrowStatement statementNode); abstract T processTryStatement(TryStatement statementNode); abstract T processUnaryExpression(UnaryExpression exprNode); abstract T processVariableDeclaration(VariableDeclaration declarationNode); abstract T processVariableInitializer(VariableInitializer initializerNode); abstract T processWhileLoop(WhileLoop loopNode); abstract T processWithStatement(WithStatement statementNode); abstract T processIllegalToken(AstNode node); public T process(AstNode node) { switch (node.getType()) { case Token.ADD: case Token.AND: case Token.BITAND: case Token.BITOR: case Token.BITXOR: case Token.COMMA: case Token.DIV: case Token.EQ: case Token.GE: case Token.GT: case Token.IN: case Token.INSTANCEOF: case Token.LE: case Token.LSH: case Token.LT: case Token.MOD: case Token.MUL: case Token.NE: case Token.OR: case Token.RSH: case Token.SHEQ: case Token.SHNE: case Token.SUB: case Token.URSH: return processInfixExpression((InfixExpression) node); case Token.ARRAYLIT: return processArrayLiteral((ArrayLiteral) node); case Token.ASSIGN: case Token.ASSIGN_ADD: case Token.ASSIGN_BITAND: case Token.ASSIGN_BITOR: case Token.ASSIGN_BITXOR: case Token.ASSIGN_DIV: case Token.ASSIGN_LSH: case Token.ASSIGN_MOD: case Token.ASSIGN_MUL: case Token.ASSIGN_RSH: case Token.ASSIGN_SUB: case Token.ASSIGN_URSH: return processAssignment((Assignment) node); case Token.BITNOT: case Token.DEC: case Token.DELPROP: case Token.INC: case Token.NEG: case Token.NOT: case Token.POS: case Token.TYPEOF: case Token.VOID: return processUnaryExpression((UnaryExpression) node); case Token.BLOCK: if (node instanceof Block) { return processBlock((Block) node); } else if

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS> private static final Set<String> CONSTRUCTORS_WITHOUT_SIDE_EFFECTS = new HashSet<String>(Arrays.asList( "Array", "Date", "Error", "Object", "RegExp", "XMLHttpRequest")); // Utility class; do not instantiate. private NodeUtil() {} /** * Gets the boolean value of a node that represents a expression. This method * effectively emulates the <code>Boolean()</code> JavaScript cast function. * Note: unlike getBooleanValue this function does not return UNKNOWN * for expressions with side-effects. */ static TernaryValue getImpureBooleanValue(Node n) { switch (n.getType()) { case Token.ASSIGN: case Token.COMMA: // For ASSIGN and COMMA the value is the value of the RHS. return getImpureBooleanValue(n.getLastChild()); case Token.NOT: TernaryValue value = getImpureBooleanValue(n.getLastChild()); return value.not(); case Token.AND: { TernaryValue lhs = getImpureBooleanValue(n.getFirstChild()); TernaryValue rhs = getImpureBooleanValue(n.getLastChild()); return lhs.and(rhs); } case Token.OR: { TernaryValue lhs = getImpureBooleanValue(n.getFirstChild()); TernaryValue rhs = getImpureBooleanValue(n.getLastChild()); return lhs.or(rhs); } case Token.HOOK: { TernaryValue trueValue = getImpureBooleanValue( n.getFirstChild().getNext()); TernaryValue falseValue = getImpureBooleanValue(n.getLastChild()); if (trueValue.equals(falseValue)) { return trueValue; } else { return TernaryValue.UNKNOWN; } } case Token.ARRAYLIT: case Token.OBJECTLIT: // ignoring side-effects return TernaryValue.TRUE; default: return getPureBooleanValue(n); } } /** * Gets the boolean value of a node that represents a literal. This method * effectively emulates the <code>Boolean()</code> JavaScript cast function * except it return UNKNOWN for known values with side-effects, use * getExpressionBooleanValue if you don't care about side

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS>-effects. */ static TernaryValue getPureBooleanValue(Node n) { switch (n.getType()) { case Token.STRING: return TernaryValue.forBoolean(n.getString().length() > 0); case Token.NUMBER: return TernaryValue.forBoolean(n.getDouble() != 0); case Token.NOT: return getPureBooleanValue(n.getLastChild()).not(); case Token.NULL: case Token.FALSE: case Token.VOID: return TernaryValue.FALSE; case Token.NAME: String name = n.getString(); if ("undefined".equals(name) || "NaN".equals(name)) { // We assume here that programs don't change the value of the keyword // undefined to something other than the value undefined. return TernaryValue.FALSE; } else if ("Infinity".equals(name)) { return TernaryValue.TRUE; } break; case Token.TRUE: case Token.REGEXP: return TernaryValue.TRUE; case Token.ARRAYLIT: case Token.OBJECTLIT: if (!mayHaveSideEffects(n)) { return TernaryValue.TRUE; } } return TernaryValue.UNKNOWN; } /** * Gets the value of a node as a String, or null if it cannot be converted. * When it returns a non-null String, this method effectively emulates the * <code>String()</code> JavaScript cast function. */ static String getStringValue(Node n) { // TODO(user): regex literals as well. switch (n.getType()) { case Token.STRING: return n.getString(); case Token.NAME: String name = n.getString(); if ("undefined".equals(name) || "Infinity".equals(name) || "NaN".equals(name)) { return name; } break; case Token.NUMBER: return getStringValue(n.getDouble()); case Token.FALSE: case Token.TRUE: case Token.NULL: return Node.tokenToName(n.getType()); case Token.VOID: return "undefined"; case Token.NOT: TernaryValue child = getPureBooleanValue(n.getFirstChild()); if (child != TernaryValue

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS>.UNKNOWN) { return child.toBoolean(true) ? "false" : "true"; // reversed. } break; case Token.ARRAYLIT: return arrayToString(n); case Token.OBJECTLIT: return "[object Object]"; } return null; } static String getStringValue(double value) { long longValue = (long) value; // Return "1" instead of "1.0" if (longValue == value) { return Long.toString(longValue); } else { return Double.toString(value); } } /** * When converting arrays to string using Array.prototype.toString or * Array.prototype.join, the rules for conversion to String are different * than converting each element individually. Specifically, "null" and * "undefined" are converted to an empty string. * @param n A node that is a member of an Array. * @return The string representation. */ static String getArrayElementStringValue(Node n) { return (NodeUtil.isNullOrUndefined(n) || n.getType() == Token.EMPTY) ? "" : getStringValue(n); } static String arrayToString(Node literal) { Node first = literal.getFirstChild(); StringBuilder result = new StringBuilder(); int nextSlot = 0; int nextSkipSlot = 0; for (Node n = first; n != null; n = n.getNext()) { String childValue = getArrayElementStringValue(n); if (childValue == null) { return null; } if (n != first) { result.append(','); } result.append(childValue); nextSlot++; } return result.toString(); } /** * Gets the value of a node as a Number, or null if it cannot be converted. * When it returns a non-null Double, this method effectively emulates the * <code>Number()</code> JavaScript cast function. */ static Double getNumberValue(Node n) { switch (n.getType()) { case Token.TRUE: return 1.0; case Token.FALSE: case Token.NULL: return 0.0; case Token.NUMBER: return n.getDouble(); case Token.VOID: if (mayHave

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS>SideEffects(n.getFirstChild())) { return null; } else { return Double.NaN; } case Token.NAME: // Check for known constants String name = n.getString(); if (name.equals("undefined")) { return Double.NaN; } if (name.equals("NaN")) { return Double.NaN; } if (name.equals("Infinity")) { return Double.POSITIVE_INFINITY; } return null; case Token.NEG: if (n.getChildCount() == 1 && n.getFirstChild().getType() == Token.NAME && n.getFirstChild().getString().equals("Infinity")) { return Double.NEGATIVE_INFINITY; } return null; case Token.NOT: TernaryValue child = getPureBooleanValue(n.getFirstChild()); if (child != TernaryValue.UNKNOWN) { return child.toBoolean(true) ? 0.0 : 1.0; // reversed. } break; case Token.STRING: return getStringNumberValue(n.getString()); case Token.ARRAYLIT: case Token.OBJECTLIT: String value = getStringValue(n); return value != null ? getStringNumberValue(value) : null; } return null; } static Double getStringNumberValue(String rawJsString) { if (rawJsString.contains("\u000b")) { // vertical tab is not always whitespace return null; } String s = trimJsWhiteSpace(rawJsString); // return ScriptRuntime.toNumber(s); if (s.length() == 0) { return 0.0; } if (s.length() > 2 && s.charAt(0) == '0' && (s.charAt(1) == 'x' || s.charAt(1) == 'X')) { // Attempt to convert hex numbers. try { return Double.valueOf(Integer.parseInt(s.substring(2), 16)); } catch (NumberFormatException e) { return Double.NaN; } } if (s.length() > 3 && (s.charAt(0) == '-' || s.charAt(0) == '+') && s.charAt(1) == '0'

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS> && (s.charAt(2) == 'x' || s.charAt(2) == 'X')) { // hex numbers with explicit signs vary between browsers. return null; } // FireFox and IE treat the "Infinity" differently. FireFox is case // insensitive, but IE treats "infinity" as NaN. So leave it alone. if (s.equals("infinity") || s.equals("-infinity") || s.equals("+infinity")) { return null; } try { return Double.parseDouble(s); } catch (NumberFormatException e) { return Double.NaN; } } static String trimJsWhiteSpace(String s) { int start = 0; int end = s.length(); while (end > 0 && isStrWhiteSpaceChar(s.charAt(end - 1)) == TernaryValue.TRUE) { end--; } while (start < end && isStrWhiteSpaceChar(s.charAt(start)) == TernaryValue.TRUE) { start++; } return s.substring(start, end); } /** * Copied from Rhino's ScriptRuntime */ static TernaryValue isStrWhiteSpaceChar(int c) { switch (c) { case '\u000B': // <VT> return TernaryValue.UNKNOWN; // IE says "no", EcmaScript says "yes" case ' ': // <SP> case '\n': // <LF> case '\r': // <CR> case '\t': // <TAB> case '\u00A0': // <NBSP> case '\u000C': // <FF> case '\u2028': // <LS> case '\u2029': // <PS> case '\uFEFF': // <BOM> return TernaryValue.TRUE; default: return (Character.getType(c) == Character.SPACE_SEPARATOR) ? TernaryValue.TRUE : TernaryValue.FALSE; } } /** * Gets the function's name. This method recognizes five forms: * <ul> * <li>{@code function name() ...}</li> * <li>{@code var name = function() ...}</

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS> switch (parent.getType()) { case Token.SET: case Token.GET: case Token.STRING: // Return the name of the literal's key. return parent.getString(); case Token.NUMBER: return getStringValue(parent); } return null; } /** * Returns true if this is an immutable value. */ static boolean isImmutableValue(Node n) { switch (n.getType()) { case Token.STRING: case Token.NUMBER: case Token.NULL: case Token.TRUE: case Token.FALSE: return true; case Token.NOT: return isImmutableValue(n.getFirstChild()); case Token.VOID: case Token.NEG: return isImmutableValue(n.getFirstChild()); case Token.NAME: String name = n.getString(); // We assume here that programs don't change the value of the keyword // undefined to something other than the value undefined. return "undefined".equals(name) || "Infinity".equals(name) || "NaN".equals(name); } return false; } /** * Returns true if this is a literal value. We define a literal value * as any node that evaluates to the same thing regardless of when or * where it is evaluated. So /xyz/ and [3, 5] are literals, but * the name a is not. * * Function literals do not meet this definition, because they * lexically capture variables. For example, if you have * <code> * function() { return a; } * </code> * If it is evaluated in a different scope, then it * captures a different variable. Even if the function did not read * any captured vairables directly, it would still fail this definition, * because it affects the lifecycle of variables in the enclosing scope. * * However, a function literal with respect to a particular scope is * a literal. * * @param includeFunctions If true, all function expressions will be * treated as literals. */ static boolean isLiteralValue(Node n, boolean includeFunctions) { switch (n.getType()) { case Token.ARRAYLIT: for (Node child = n.getFirstChild(); child != null; child = child.getNext()) {

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS> if (child.getType() != Token.EMPTY && !isLiteralValue(child, includeFunctions)) { return false; } } return true; case Token.REGEXP: // Return true only if all children are const. for (Node child = n.getFirstChild(); child != null; child = child.getNext()) { if (!isLiteralValue(child, includeFunctions)) { return false; } } return true; case Token.OBJECTLIT: // Return true only if all values are const. for (Node child = n.getFirstChild(); child != null; child = child.getNext()) { if (!isLiteralValue(child.getFirstChild(), includeFunctions)) { return false; } } return true; case Token.FUNCTION: return includeFunctions && !NodeUtil.isFunctionDeclaration(n); default: return isImmutableValue(n); } } /** * Determines whether the given value may be assigned to a define. * * @param val The value being assigned. * @param defines The list of names of existing defines. */ static boolean isValidDefineValue(Node val, Set<String> defines) { switch (val.getType()) { case Token.STRING: case Token.NUMBER: case Token.TRUE: case Token.FALSE: return true; // Binary operators are only valid if both children are valid. case Token.ADD: case Token.BITAND: case Token.BITNOT: case Token.BITOR: case Token.BITXOR: case Token.DIV: case Token.EQ: case Token.GE: case Token.GT: case Token.LE: case Token.LSH: case Token.LT: case Token.MOD: case Token.MUL: case Token.NE: case Token.RSH: case Token.SHEQ: case Token.SHNE: case Token.SUB: case Token.URSH: return isValidDefineValue(val.getFirstChild(), defines) && isValidDefineValue(val.getLastChild(), defines); // Uniary operators are valid if the child is valid. case Token.NOT: case Token.NEG: case Token.POS: return isValidDefineValue(val.getFirstChild(), defines

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS>); // Names are valid if and only if they are defines themselves. case Token.NAME: case Token.GETPROP: if (val.isQualifiedName()) { return defines.contains(val.getQualifiedName()); } } return false; } /** * Returns whether this a BLOCK node with no children. * * @param block The node. */ static boolean isEmptyBlock(Node block) { if (block.getType() != Token.BLOCK) { return false; } for (Node n = block.getFirstChild(); n != null; n = n.getNext()) { if (n.getType() != Token.EMPTY) { return false; } } return true; } static boolean isSimpleOperator(Node n) { return isSimpleOperatorType(n.getType()); } /** * A "simple" operator is one whose children are expressions, * has no direct side-effects (unlike '+='), and has no * conditional aspects (unlike '||'). */ static boolean isSimpleOperatorType(int type) { switch (type) { case Token.ADD: case Token.BITAND: case Token.BITNOT: case Token.BITOR: case Token.BITXOR: case Token.COMMA: case Token.DIV: case Token.EQ: case Token.GE: case Token.GETELEM: case Token.GETPROP: case Token.GT: case Token.INSTANCEOF: case Token.LE: case Token.LSH: case Token.LT: case Token.MOD: case Token.MUL: case Token.NE: case Token.NOT: case Token.RSH: case Token.SHEQ: case Token.SHNE: case Token.SUB: case Token.TYPEOF: case Token.VOID: case Token.POS: case Token.NEG: case Token.URSH: return true; default: return false; } } /** * Creates an EXPR_RESULT. * * @param child The expression itself. * @return Newly created EXPR node with the child as subexpression. */ public static Node newExpr(Node child) { Node expr = new Node(Token.EXPR_

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS>4 call, member () [] . */ static int precedence(int type) { switch (type) { case Token.COMMA: return 0; case Token.ASSIGN_BITOR: case Token.ASSIGN_BITXOR: case Token.ASSIGN_BITAND: case Token.ASSIGN_LSH: case Token.ASSIGN_RSH: case Token.ASSIGN_URSH: case Token.ASSIGN_ADD: case Token.ASSIGN_SUB: case Token.ASSIGN_MUL: case Token.ASSIGN_DIV: case Token.ASSIGN_MOD: case Token.ASSIGN: return 1; case Token.HOOK: return 2; // ?: operator case Token.OR: return 3; case Token.AND: return 4; case Token.BITOR: return 5; case Token.BITXOR: return 6; case Token.BITAND: return 7; case Token.EQ: case Token.NE: case Token.SHEQ: case Token.SHNE: return 8; case Token.LT: case Token.GT: case Token.LE: case Token.GE: case Token.INSTANCEOF: case Token.IN: return 9; case Token.LSH: case Token.RSH: case Token.URSH: return 10; case Token.SUB: case Token.ADD: return 11; case Token.MUL: case Token.MOD: case Token.DIV: return 12; case Token.INC: case Token.DEC: case Token.NEW: case Token.DELPROP: case Token.TYPEOF: case Token.VOID: case Token.NOT: case Token.BITNOT: case Token.POS: case Token.NEG: return 13; case Token.ARRAYLIT: case Token.CALL: case Token.EMPTY: case Token.FALSE: case Token.FUNCTION: case Token.GETELEM: case Token.GETPROP: case Token.GET_REF: case Token.IF: case Token.LP: case Token.NAME: case Token.NULL: case Token.NUMBER: case Token.OBJECTLIT: case

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS> Token.REGEXP: case Token.STRING: case Token.THIS: case Token.TRUE: return 15; default: throw new Error("Unknown precedence for " + Node.tokenToName(type) + " (type " + type + ")"); } } /** * Apply the supplied predicate against the potential * all possible result of the expression. */ static boolean valueCheck(Node n, Predicate<Node> p) { switch (n.getType()) { case Token.ASSIGN: case Token.COMMA: return valueCheck(n.getLastChild(), p); case Token.AND: case Token.OR: return valueCheck(n.getFirstChild(), p) && valueCheck(n.getLastChild(), p); case Token.HOOK: return valueCheck(n.getFirstChild().getNext(), p) && valueCheck(n.getLastChild(), p); default: return p.apply(n); } } static class NumbericResultPredicate implements Predicate<Node> { public boolean apply(Node n) { return isNumericResultHelper(n); } } static final NumbericResultPredicate NUMBERIC_RESULT_PREDICATE = new NumbericResultPredicate(); /** * Returns true if the result of node evaluation is always a number */ static boolean isNumericResult(Node n) { return valueCheck(n, NUMBERIC_RESULT_PREDICATE); } static boolean isNumericResultHelper(Node n) { switch (n.getType()) { case Token.ADD: return !mayBeString(n.getFirstChild()) && !mayBeString(n.getLastChild()); case Token.BITNOT: case Token.BITOR: case Token.BITXOR: case Token.BITAND: case Token.LSH: case Token.RSH: case Token.URSH: case Token.SUB: case Token.MUL: case Token.MOD: case Token.DIV: case Token.INC: case Token.DEC: case Token.POS: case Token.NEG: case Token.NUMBER: return true; case Token.NAME: String name = n.getString(); if (name.equals("NaN")) { return true; } if (name

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS>.equals("Infinity")) { return true; } return false; default: return false; } } static class BooleanResultPredicate implements Predicate<Node> { public boolean apply(Node n) { return isBooleanResultHelper(n); } } static final BooleanResultPredicate BOOLEAN_RESULT_PREDICATE = new BooleanResultPredicate(); /** * @return Whether the result of node evaluation is always a boolean */ static boolean isBooleanResult(Node n) { return valueCheck(n, BOOLEAN_RESULT_PREDICATE); } static boolean isBooleanResultHelper(Node n) { switch (n.getType()) { // Primitives case Token.TRUE: case Token.FALSE: // Comparisons case Token.EQ: case Token.NE: case Token.SHEQ: case Token.SHNE: case Token.LT: case Token.GT: case Token.LE: case Token.GE: // Queryies case Token.IN: case Token.INSTANCEOF: // Inversion case Token.NOT: // delete operator returns a boolean. case Token.DELPROP: return true; default: return false; } } static boolean isUndefined(Node n) { switch (n.getType()) { case Token.VOID: return true; case Token.NAME: return n.getString().equals("undefined"); } return false; } static boolean isNull(Node n) { return n.getType() == Token.NULL; } static boolean isNullOrUndefined(Node n) { return isNull(n) || isUndefined(n); } static class MayBeStringResultPredicate implements Predicate<Node> { public boolean apply(Node n) { return mayBeStringHelper(n); } } static final MayBeStringResultPredicate MAY_BE_STRING_PREDICATE = new MayBeStringResultPredicate(); /** * @returns Whether the results is possibly a string. */ static boolean mayBeString(Node n) { return mayBeString(n, true); } static boolean mayBeString(Node n, boolean recurse) { if (recurse) { return valueCheck(n, MAY_BE_STRING_PRED

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS>ICATE); } else { return mayBeStringHelper(n); } } static boolean mayBeStringHelper(Node n) { return !isNumericResult(n) && !isBooleanResult(n) && !isUndefined(n) && !isNull(n); } /** * Returns true if the operator is associative. * e.g. (a * b) * c = a * (b * c) * Note: "+" is not associative because it is also the concatenation * for strings. e.g. "a" + (1 + 2) is not "a" + 1 + 2 */ static boolean isAssociative(int type) { switch (type) { case Token.MUL: case Token.AND: case Token.OR: case Token.BITOR: case Token.BITXOR: case Token.BITAND: return true; default: return false; } } /** * Returns true if the operator is commutative. * e.g. (a * b) * c = c * (b * a) * Note 1: "+" is not commutative because it is also the concatenation * for strings. e.g. "a" + (1 + 2) is not "a" + 1 + 2 * Note 2: only operations on literals and pure functions are commutative. */ static boolean isCommutative(int type) { switch (type) { case Token.MUL: case Token.BITOR: case Token.BITXOR: case Token.BITAND: return true; default: return false; } } static boolean isAssignmentOp(Node n) { switch (n.getType()){ case Token.ASSIGN: case Token.ASSIGN_BITOR: case Token.ASSIGN_BITXOR: case Token.ASSIGN_BITAND: case Token.ASSIGN_LSH: case Token.ASSIGN_RSH: case Token.ASSIGN_URSH: case Token.ASSIGN_ADD: case Token.ASSIGN_SUB: case Token.ASSIGN_MUL: case Token.ASSIGN_DIV: case Token.ASSIGN_MOD: return true; } return false; }

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS> representation. * * @param operator the operator's token value to convert * @return the string representation or {@code null} if the token value is * not an operator */ static String opToStr(int operator) { switch (operator) { case Token.BITOR: return "|"; case Token.OR: return "||"; case Token.BITXOR: return "^"; case Token.AND: return "&&"; case Token.BITAND: return "&"; case Token.SHEQ: return "==="; case Token.EQ: return "=="; case Token.NOT: return "!"; case Token.NE: return "!="; case Token.SHNE: return "!=="; case Token.LSH: return "<<"; case Token.IN: return "in"; case Token.LE: return "<="; case Token.LT: return "<"; case Token.URSH: return ">>>"; case Token.RSH: return ">>"; case Token.GE: return ">="; case Token.GT: return ">"; case Token.MUL: return "*"; case Token.DIV: return "/"; case Token.MOD: return "%"; case Token.BITNOT: return "~"; case Token.ADD: return "+"; case Token.SUB: return "-"; case Token.POS: return "+"; case Token.NEG: return "-"; case Token.ASSIGN: return "="; case Token.ASSIGN_BITOR: return "|="; case Token.ASSIGN_BITXOR: return "^="; case Token.ASSIGN_BITAND: return "&="; case Token.ASSIGN_LSH: return "<<="; case Token.ASSIGN_RSH: return ">>="; case Token.ASSIGN_URSH: return ">>>="; case Token.ASSIGN_ADD: return "+="; case Token.ASSIGN_SUB: return "-="; case Token.ASSIGN_MUL: return "*="; case Token.ASSIGN_DIV: return "/="; case Token.ASSIGN_MOD: return "%="; case Token.VOID: return "void"; case Token.TYPEOF: return "typeof"; case Token.INSTANCEOF: return "instanceof"; default: return null; } } /** * Converts an operator's

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS> token value (see {@link Token}) to a string * representation or fails. * * @param operator the operator's token value to convert * @return the string representation * @throws Error if the token value is not an operator */ static String opToStrNoFail(int operator) { String res = opToStr(operator); if (res == null) { throw new Error("Unknown op " + operator + ": " + Token.name(operator)); } return res; } /** * @return true if n or any of its children are of the specified type */ static boolean containsType(Node node, int type, Predicate<Node> traverseChildrenPred) { return has(node, new MatchNodeType(type), traverseChildrenPred); } /** * @return true if n or any of its children are of the specified type */ static boolean containsType(Node node, int type) { return containsType(node, type, Predicates.<Node>alwaysTrue()); } /** * Given a node tree, finds all the VAR declarations in that tree that are * not in an inner scope. Then adds a new VAR node at the top of the current * scope that redeclares them, if necessary. */ static void redeclareVarsInsideBranch(Node branch) { Collection<Node> vars = getVarsDeclaredInBranch(branch); if (vars.isEmpty()) { return; } Node parent = getAddingRoot(branch); for (Node nameNode : vars) { Node var = new Node( Token.VAR, Node.newString(Token.NAME, nameNode.getString()) .copyInformationFrom(nameNode)) .copyInformationFrom(nameNode); copyNameAnnotations(nameNode, var.getFirstChild()); parent.addChildToFront(var); } } /** * Copy any annotations that follow a named value. * @param source * @param destination */ static void copyNameAnnotations(Node source, Node destination) { if (source.getBooleanProp(Node.IS_CONSTANT_NAME)) { destination.putBooleanProp(Node.IS_CONSTANT_NAME, true); } } /** * Gets a Node at the top of the current scope where we can add new var * declarations

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS> as children. */ private static Node getAddingRoot(Node n) { Node addingRoot = null; Node ancestor = n; while (null != (ancestor = ancestor.getParent())) { int type = ancestor.getType(); if (type == Token.SCRIPT) { addingRoot = ancestor; break; } else if (type == Token.FUNCTION) { addingRoot = ancestor.getLastChild(); break; } } // make sure that the adding root looks ok Preconditions.checkState(addingRoot.getType() == Token.BLOCK || addingRoot.getType() == Token.SCRIPT); Preconditions.checkState(addingRoot.getFirstChild() == null || addingRoot.getFirstChild().getType() != Token.SCRIPT); return addingRoot; } /** Creates function name(params_0, ..., params_n) { body }. */ public static Node newFunctionNode(String name, List<Node> params, Node body, int lineno, int charno) { Node parameterParen = new Node(Token.LP, lineno, charno); for (Node param : params) { parameterParen.addChildToBack(param); } Node function = new Node(Token.FUNCTION, lineno, charno); function.addChildrenToBack( Node.newString(Token.NAME, name, lineno, charno)); function.addChildToBack(parameterParen); function.addChildToBack(body); return function; } /** * Creates a node representing a qualified name. * * @param name A qualified name (e.g. "foo" or "foo.bar.baz") * @param lineno The source line offset. * @param charno The source character offset from start of the line. * @return A NAME or GETPROP node */ public static Node newQualifiedNameNode( CodingConvention convention, String name, int lineno, int charno) { int endPos = name.indexOf('.'); if (endPos == -1) { return newName(convention, name, lineno, charno); } Node node = newName( convention, name.substring(0, endPos), lineno, charno); int startPos; do { startPos = endPos + 1; endPos = name.indexOf('.', startPos); String part =

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS> (endPos == -1 ? name.substring(startPos) : name.substring(startPos, endPos)); Node propNode = Node.newString(Token.STRING, part, lineno, charno); if (convention.isConstantKey(part)) { propNode.putBooleanProp(Node.IS_CONSTANT_NAME, true); } node = new Node(Token.GETPROP, node, propNode, lineno, charno); } while (endPos != -1); return node; } /** * Creates a node representing a qualified name, copying over the source * location information from the basis node and assigning the given original * name to the node. * * @param name A qualified name (e.g. "foo" or "foo.bar.baz") * @param basisNode The node that represents the name as currently found in * the AST. * @param originalName The original name of the item being represented by the * NAME node. Used for debugging information. * * @return A NAME or GETPROP node */ static Node newQualifiedNameNode( CodingConvention convention, String name, Node basisNode, String originalName) { Node node = newQualifiedNameNode(convention, name, -1, -1); setDebugInformation(node, basisNode, originalName); return node; } /** * Gets the root node of a qualified name. Must be either NAME or THIS. */ static Node getRootOfQualifiedName(Node qName) { for (Node current = qName; true; current = current.getFirstChild()) { int type = current.getType(); if (type == Token.NAME || type == Token.THIS) { return current; } Preconditions.checkState(type == Token.GETPROP); } } /** * Sets the debug information (source file info and orignal name) * on the given node. * * @param node The node on which to set the debug information. * @param basisNode The basis node from which to copy the source file info. * @param originalName The original name of the node. */ static void setDebugInformation(Node node, Node basisNode, String originalName) { node.copyInformationFromForTree(basisNode);

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS> * some constructor. */ static boolean isPrototypePropertyDeclaration(Node n) { if (!isExprAssign(n)) { return false; } return isPrototypeProperty(n.getFirstChild().getFirstChild()); } static boolean isPrototypeProperty(Node n) { String lhsString = n.getQualifiedName(); if (lhsString == null) { return false; } int prototypeIdx = lhsString.indexOf(".prototype."); return prototypeIdx != -1; } /** * @return The class name part of a qualified prototype name. */ static Node getPrototypeClassName(Node qName) { Node cur = qName; while (isGetProp(cur)) { if (cur.getLastChild().getString().equals("prototype")) { return cur.getFirstChild(); } else { cur = cur.getFirstChild(); } } return null; } /** * @return The string property name part of a qualified prototype name. */ static String getPrototypePropertyName(Node qName) { String qNameStr = qName.getQualifiedName(); int prototypeIdx = qNameStr.lastIndexOf(".prototype."); int memberIndex = prototypeIdx + ".prototype".length() + 1; return qNameStr.substring(memberIndex); } /** * Create a node for an empty result expression: * "void 0" */ static Node newUndefinedNode(Node srcReferenceNode) { Node node = new Node(Token.VOID, Node.newNumber(0)); if (srcReferenceNode != null) { node.copyInformationFromForTree(srcReferenceNode); } return node; } /** * Create a VAR node containing the given name and initial value expression. */ static Node newVarNode(String name, Node value) { Node nodeName = Node.newString(Token.NAME, name); if (value != null) { Preconditions.checkState(value.getNext() == null); nodeName.addChildToBack(value); nodeName.copyInformationFrom(value); } Node var = new Node(Token.VAR, nodeName) .copyInformationFrom(nodeName); return var; } /** * A predicate for matching name nodes with the specified node. */ private static class MatchNameNode implements Predicate

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS><Node>{ final String name; MatchNameNode(String name){ this.name = name; } public boolean apply(Node n) { return n.getType() == Token.NAME && n.getString().equals(name); } } /** * A predicate for matching nodes with the specified type. */ static class MatchNodeType implements Predicate<Node>{ final int type; MatchNodeType(int type){ this.type = type; } public boolean apply(Node n) { return n.getType() == type; } } /** * A predicate for matching var or function declarations. */ static class MatchDeclaration implements Predicate<Node> { public boolean apply(Node n) { return isFunctionDeclaration(n) || n.getType() == Token.VAR; } } /** * A predicate for matching anything except function nodes. */ static class MatchNotFunction implements Predicate<Node>{ public boolean apply(Node n) { return !isFunction(n); } } /** * A predicate for matching statements without exiting the current scope. */ static class MatchShallowStatement implements Predicate<Node>{ public boolean apply(Node n) { Node parent = n.getParent(); return n.getType() == Token.BLOCK || (!isFunction(n) && (parent == null || isControlStructure(parent) || isStatementBlock(parent))); } } /** * Finds the number of times a type is referenced within the node tree. */ static int getNodeTypeReferenceCount( Node node, int type, Predicate<Node> traverseChildrenPred) { return getCount(node, new MatchNodeType(type), traverseChildrenPred); } /** * Whether a simple name is referenced within the node tree. */ static boolean isNameReferenced(Node node, String name, Predicate<Node> traverseChildrenPred) { return has(node, new MatchNameNode(name), traverseChildrenPred); } /** * Whether a simple name is referenced within the node tree. */ static boolean isNameReferenced(Node node, String name) { return isNameReferenced(node, name, Predicates.<Node>alwaysTrue()); } /** * Finds the number of times a simple name is referenced within the node tree. */

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS> != null) { sourceName = (String) n.getProp(Node.SOURCENAME_PROP); n = n.getParent(); } return sourceName; } /** * A new CALL node with the "FREE_CALL" set based on call target. */ static Node newCallNode(Node callTarget, Node... parameters) { boolean isFreeCall = isName(callTarget); Node call = new Node(Token.CALL, callTarget); call.putBooleanProp(Node.FREE_CALL, isFreeCall); for (Node parameter : parameters) { call.addChildToBack(parameter); } return call; } /** * @return Whether the node is known to be a value that is not referenced * elsewhere. */ static boolean evaluatesToLocalValue(Node value) { return evaluatesToLocalValue(value, Predicates.<Node>alwaysFalse()); } /** * @param locals A predicate to apply to unknown local values. * @return Whether the node is known to be a value that is not a reference * outside the expression scope. */ static boolean evaluatesToLocalValue(Node value, Predicate<Node> locals) { switch (value.getType()) { case Token.ASSIGN: // A result that is aliased by a non-local name, is the effectively the // same as returning a non-local name, but this doesn't matter if the // value is immutable. return NodeUtil.isImmutableValue(value.getLastChild()) || (locals.apply(value) && evaluatesToLocalValue(value.getLastChild(), locals)); case Token.COMMA: return evaluatesToLocalValue(value.getLastChild(), locals); case Token.AND: case Token.OR: return evaluatesToLocalValue(value.getFirstChild(), locals) && evaluatesToLocalValue(value.getLastChild(), locals); case Token.HOOK: return evaluatesToLocalValue(value.getFirstChild().getNext(), locals) && evaluatesToLocalValue(value.getLastChild(), locals); case Token.INC: case Token.DEC: if (value.getBooleanProp(Node.INCRDECR_PROP)) { return evaluatesToLocalValue(value.getFirstChild(), locals); } else { return true; } case Token.THIS: return locals.apply(

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS>value); case Token.NAME: return isImmutableValue(value) || locals.apply(value); case Token.GETELEM: case Token.GETPROP: // There is no information about the locality of object properties. return locals.apply(value); case Token.CALL: return callHasLocalResult(value) || isToStringMethodCall(value) || locals.apply(value); case Token.NEW: return newHasLocalResult(value) || locals.apply(value); case Token.FUNCTION: case Token.REGEXP: case Token.ARRAYLIT: case Token.OBJECTLIT: // Literals objects with non-literal children are allowed. return true; case Token.DELPROP: case Token.IN: // TODO(johnlenz): should IN operator be included in #isSimpleOperator? return true; default: // Other op force a local value: // x = '' + g (x is now an local string) // x -= g (x is now an local number) if (isAssignmentOp(value) || isSimpleOperator(value) || isImmutableValue(value)) { return true; } throw new IllegalStateException( "Unexpected expression node" + value + "\n parent:" + value.getParent()); } } /** * Given the first sibling, this returns the nth * sibling or null if no such sibling exists. * This is like "getChildAtIndex" but returns null for non-existent indexes. */ private static Node getNthSibling(Node first, int index) { Node sibling = first; while (index != 0 && sibling != null) { sibling = sibling.getNext(); index--; } return sibling; } /** * Given the function, this returns the nth * argument or null if no such parameter exists. */ static Node getArgumentForFunction(Node function, int index) { Preconditions.checkState(isFunction(function)); return getNthSibling( function.getFirstChild().getNext().getFirstChild(), index); } /** * Given the new or call, this returns the nth * argument of the call or null if no such argument exists. */ static Node getArgumentForCallOrNew(Node call, int index) { Preconditions

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS> given request traced in multiple threads. (the results * will be scattered accross reports). * * Java objects do not support destructors (as in C++) so Tracer is not robust * when exceptions are thrown. Each Tracer object should be wrapped in a * try/finally block so that if an exception is thrown, the Tracer.stop() * method is guaranteed to be called. * * <p>A thread must call {@link Tracer#initCurrentThreadTrace()} to enable the * Tracer logging, otherwise Tracer does nothing. The requirement to call * {@code initCurrentThreadTrace} avoids the situtation where Tracer is called * without the explicit knowledge of the application authors because they * happen to use a class in another package that uses Tracer. If {@link * Tracer#logCurrentThreadTrace} is called without calling {@link * Tracer#initCurrentThreadTrace()}, then a Third Eye WARNING message is logged, * which should help track down the problem. * */ final class Tracer { // package-private for access from unit tests static final Logger logger = Logger.getLogger(Tracer.class.getName()); /** * Whether pretty printing is enabled. This is intended to be set once * at application startup. */ private static volatile boolean defaultPrettyPrint; /* This list is guaranteed to only increase in length. It contains * a list of additional statistics that the user wants to keep track * of. */ private static List<TracingStatistic> extraTracingStatistics = new CopyOnWriteArrayList<TracingStatistic>(); /** Values returned by extraTracingStatistics */ private long[] extraTracingValues; /** The type for grouping traces, may be null */ private final @Nullable String type; /** A comment string for the report */ private final String comment; /** Start time of the trace */ private final long startTimeMs; /** Stop time of the trace, non-final */ private long stopTimeMs; /** * Record our starter thread in order to trap Traces that are started in one * thread and stopped in another */ final Thread startThread; /** * We limit the number of events in a Trace in order to catch memory * leaks (a thread that keeps logging events and never clears them). * This number is arbitrary and can

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS> be increased if necessary (though * if there are more than 1000 events then the Tracer is probably being * misused). */ static final int MAX_TRACE_SIZE = 1000; /** * For unit testing. Can't use {@link com.google.common.time.Clock} because * this code is in base and has minimal dependencies. */ static interface InternalClock { long currentTimeMillis(); } /** * Default clock that calls through to the system clock. Can be overridden * in unit tests. */ static InternalClock clock = new InternalClock() { public long currentTimeMillis() { return System.currentTimeMillis(); } }; /** * Create and start a tracer. * Both type and comment may be null. See class comment for usage. * * @param type The type for totalling * @param comment Comment about this tracer */ Tracer(@Nullable String type, @Nullable String comment) { this.type = type; this.comment = comment == null ? "" : comment; startTimeMs = clock.currentTimeMillis(); startThread = Thread.currentThread(); if (!extraTracingStatistics.isEmpty()) { int size = extraTracingStatistics.size(); extraTracingValues = new long[size]; int i = 0; for (TracingStatistic tracingStatistic : extraTracingStatistics) { extraTracingValues[i] = tracingStatistic.start(startThread); i++; } } ThreadTrace trace = getThreadTrace(); // Do nothing if the current thread trace wasn't initialized. if (!trace.isInitialized()) { return; } // Check if we are creating too many Tracers. if (trace.events.size() >= MAX_TRACE_SIZE) { logger.log(Level.WARNING, "Giant thread trace. Too many Tracers created. " + "Clearing to avoid memory leak.", new Throwable(trace.toString())); trace.truncateEvents(); } // Check if we forgot to close the Tracers. if (trace.outstandingEvents.size() >= MAX_TRACE_SIZE) { logger.log(Level.WARNING, "Too many outstanding Tracers. Tracer.stop() is missing " + "or Tracer.stop() is not wrapped in a

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS>(); // Do nothing if the thread trace was not initialized. if (!trace.isInitialized()) { return 0; } stopTimeMs = clock.currentTimeMillis(); if (extraTracingValues != null) { // We use extraTracingValues.length rather than // extraTracingStatistics.size() because a new statistic may // have been added for (int i = 0; i < extraTracingValues.length; i++) { long value = extraTracingStatistics.get(i).stop(startThread); extraTracingValues[i] = value - extraTracingValues[i]; } } // Do nothing if the thread trace was not initialized. if (!trace.isInitialized()) { return 0; } trace.endEvent(this, silence_threshold); return stopTimeMs - startTimeMs; } /** Stop the trace using the default silence_threshold * * @return The time that this trace actually ran. */ long stop() { return stop(-1); } @Override public String toString() { if (type == null) { return comment; } else { return "[" + type + "] " + comment; } } static void setDefaultSilenceThreshold(int threshold) { getThreadTrace().defaultSilenceThreshold = threshold; } /** * Initialize the trace associated with the current thread by clearing * out any existing trace. There shouldn't be a trace so if one is * found we log it as an error. */ static void initCurrentThreadTrace() { ThreadTrace events = getThreadTrace(); if (!events.isEmpty()) { logger.log(Level.WARNING, "Non-empty timer log:\n" + events, new Throwable()); clearThreadTrace(); // Grab a new thread trace if we find a previous non-empty ThreadTrace. events = getThreadTrace(); } // Mark the thread trace as initialized. events.init(); } static void initCurrentThreadTrace(int default_silence_threshold) { initCurrentThreadTrace(); setDefaultSilenceThreshold(default_silence_threshold); } /** * Returns a timer report similar to the one described in the class comment. * * @return The timer report as a string */ static String getCurrentThreadTraceReport() {

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS> null; } /** Gets the Stat for a tracer type; never returns null */ static Stat getStatsForType(String type) { Stat stat = getThreadTrace().stats.get(type); return stat != null ? stat : ZERO_STAT; } private static final Stat ZERO_STAT = new Stat(); /** Return the sec.ms part of time (if time = "20:06:11.566", "11.566") */ private static String formatTime(long time) { int sec = (int) ((time / 1000) % 60); int ms = (int) (time % 1000); return String.format("%02d.%03d", sec, ms); } /** An event is created every time a Tracer is created or stopped */ private static final class Event { boolean isStart; // else is_stop Tracer tracer; Event(boolean start, Tracer t) { isStart = start; tracer = t; } long eventTime() { return isStart ? tracer.startTimeMs : tracer.stopTimeMs; } /** * Converts the event to a formatted string. * @param prevEventTime The time of the previous event which appears at * the left most part of the trace line. * @param indent The indentation to put before the tracer to show the * hieararchy. * @param digitsColWidth How many characters the digits should use. * @return The formatted string. */ String toString(long prevEventTime, String indent, int digitsColWidth) { StringBuilder sb = new StringBuilder(120); if (prevEventTime == -1) { appendSpaces(sb, digitsColWidth); } else { sb.append(longToPaddedString( eventTime() - prevEventTime, digitsColWidth)); } sb.append(' '); sb.append(formatTime(eventTime())); if (isStart) { sb.append(" Start "); appendSpaces(sb, digitsColWidth); sb.append(" "); } else { sb.append(" Done "); long delta = tracer.stopTimeMs - tracer.startTimeMs; sb.append(longToP

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS> event. */ void endEvent(Tracer t, int silenceThreshold) { boolean wasOutstanding = outstandingEvents.remove(t); if (!wasOutstanding) { if (isOutstandingEventsTruncated) { // The events stack overflowed and was truncated, so just log a // warning. Otherwise, we get an exception which is extremely // confusing. logger.log(Level.WARNING, "event not found, probably because the event stack " + "overflowed and was truncated", new Throwable()); } else { // throw an exception if the event was not found and the events stack // is pristine throw new IllegalStateException(); } } long elapsed = t.stopTimeMs - t.startTimeMs; if (silenceThreshold == -1) { // use default silenceThreshold = defaultSilenceThreshold; } if (elapsed < silenceThreshold) { // If this one is silent then we need to remove the start Event boolean removed = false; for (int i = 0; i < events.size(); i++) { Event e = events.get(i); if (e.tracer == t) { Preconditions.checkState(e.isStart); events.remove(i); removed = true; break; } } // Only assert if we didn't find the original and the events // weren't truncated. Preconditions.checkState(removed || isEventsTruncated); } else { events.add(new Event(false, t)); } if (t.type != null) { Stat stat = stats.get(t.type); if (stat == null) { stat = new Stat(); if (!extraTracingStatistics.isEmpty()) { stat.extraInfo = new int[extraTracingStatistics.size()]; } stats.put(t.type, stat); } stat.count++; if (typeToCountMap != null) { typeToCountMap.incrementBy(t.type, 1); } stat.clockTime += elapsed; if (typeToTimeMap != null) { typeToTimeMap.incrementBy(t.type, elapsed); } if (stat.extraInfo != null && t.extraTracingValues != null) { int overlapLength = Math.

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS>min(stat.extraInfo.length, t.extraTracingValues.length); for (int i = 0; i < overlapLength; i++) { stat.extraInfo[i] += t.extraTracingValues[i]; AtomicTracerStatMap map = extraTracingStatistics.get(i).getTracingStat(); if (map != null) { map.incrementBy(t.type, t.extraTracingValues[i]); } } } if (elapsed < silenceThreshold) { stat.silent++; if (typeToSilentMap != null) { typeToSilentMap.incrementBy(t.type, 1); } } } } boolean isEmpty() { return events.size() == 0 && outstandingEvents.size() == 0; } void truncateOutstandingEvents() { isOutstandingEventsTruncated = true; outstandingEvents.clear(); } void truncateEvents() { isEventsTruncated = true; events.clear(); } /** Produces the lovely Trace seen in the class comments */ // Nullness checker does not understand that prettyPrint => indent != null @SuppressWarnings("nullness") @Override public String toString() { int numDigits = getMaxDigits(); StringBuilder sb = new StringBuilder(); long etime = -1; LinkedList<String> indent = prettyPrint ? new LinkedList<String>() : null; for (Event e : events) { if (prettyPrint && !e.isStart && !indent.isEmpty()) { indent.pop(); } sb.append(" "); if (prettyPrint) { sb.append(e.toString(etime, Joiner.on("").join(indent), numDigits)); } else { sb.append(e.toString(etime, "", 4)); } etime = e.eventTime(); sb.append('\n'); if (prettyPrint && e.isStart) { indent.push("| "); } } if (outstandingEvents.size() != 0) { long now = clock.currentTimeMillis(); sb.append(" Unstopped timers:\n"); for (Tracer t : outstandingEvents) { sb.append(" "). append(t). append(" ("). append(now - t.startTimeMs).

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS> CodeGenerator(CodeConsumer consumer) { this(consumer, null); } /** * Insert a ECMASCRIPT 5 strict annotation. */ public void tagAsStrict() { add("'use strict';"); } void add(String str) { cc.add(str); } private void addIdentifier(String identifier) { cc.addIdentifier(identifierEscape(identifier)); } void add(Node n) { add(n, Context.OTHER); } void add(Node n, Context context) { if (!cc.continueProcessing()) { return; } int type = n.getType(); String opstr = NodeUtil.opToStr(type); int childCount = n.getChildCount(); Node first = n.getFirstChild(); Node last = n.getLastChild(); // Handle all binary operators if (opstr != null && first != last) { Preconditions.checkState( childCount == 2, "Bad binary operator \"%s\": expected 2 arguments but got %s", opstr, childCount); int p = NodeUtil.precedence(type); addLeftExpr(first, p, context); cc.addOp(opstr, true); // For right-hand-side of operations, only pass context if it's // the IN_FOR_INIT_CLAUSE one. Context rhsContext = getContextForNoInOperator(context); // Handle associativity. // e.g. if the parse tree is a * (b * c), // we can simply generate a * b * c. if (last.getType() == type && NodeUtil.isAssociative(type)) { addExpr(last, p, rhsContext); } else if (NodeUtil.isAssignmentOp(n) && NodeUtil.isAssignmentOp(last)) { // Assignments are the only right-associative binary operators addExpr(last, p, rhsContext); } else { addExpr(last, p + 1, rhsContext); } return; } cc.startSourceMapping(n); switch (type) { case Token.TRY: { Preconditions.checkState(first.getNext().getType() == Token.BLOCK && !first.getNext().hasMoreThanOneChild()); Preconditions.

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS> Token.LP: add("("); addList(first); add(")"); break; case Token.COMMA: Preconditions.checkState(childCount == 2); addList(first, false, context); break; case Token.NUMBER: Preconditions.checkState(childCount == 0); cc.addNumber(n.getDouble()); break; case Token.TYPEOF: case Token.VOID: case Token.NOT: case Token.BITNOT: case Token.POS: { // All of these unary operators are right-associative Preconditions.checkState(childCount == 1); cc.addOp(NodeUtil.opToStrNoFail(type), false); addExpr(first, NodeUtil.precedence(type)); break; } case Token.NEG: { Preconditions.checkState(childCount == 1); // It's important to our sanity checker that the code // we print produces the same AST as the code we parse back. // NEG is a weird case because Rhino parses "- -2" as "2". if (n.getFirstChild().getType() == Token.NUMBER) { cc.addNumber(-n.getFirstChild().getDouble()); } else { cc.addOp(NodeUtil.opToStrNoFail(type), false); addExpr(first, NodeUtil.precedence(type)); } break; } case Token.HOOK: { Preconditions.checkState(childCount == 3); int p = NodeUtil.precedence(type); addLeftExpr(first, p + 1, context); cc.addOp("?", true); addExpr(first.getNext(), 1); cc.addOp(":", true); addExpr(last, 1); break; } case Token.REGEXP: if (first.getType() != Token.STRING || last.getType() != Token.STRING) { throw new Error("Expected children to be strings"); } String regexp = regexpEscape(first.getString(), outputCharsetEncoder); // I only use one .add because whitespace matters if (childCount == 2) { add(regexp + last.getString()); } else { Preconditions.checkState(childCount == 1); add

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS>(regexp); } break; case Token.GET_REF: add(first); break; case Token.REF_SPECIAL: Preconditions.checkState(childCount == 1); add(first); add("."); add((String) n.getProp(Node.NAME_PROP)); break; case Token.FUNCTION: if (n.getClass() != Node.class) { throw new Error("Unexpected Node subclass."); } Preconditions.checkState(childCount == 3); boolean funcNeedsParens = (context == Context.START_OF_EXPR); if (funcNeedsParens) { add("("); } add("function"); add(first); add(first.getNext()); add(last, Context.PRESERVE_BLOCK); cc.endFunction(context == Context.STATEMENT); if (funcNeedsParens) { add(")"); } break; case Token.GET: case Token.SET: Preconditions.checkState(n.getParent().getType() == Token.OBJECTLIT); Preconditions.checkState(childCount == 1); Preconditions.checkState(first.getType() == Token.FUNCTION); // Get methods are unnamed Preconditions.checkState(first.getFirstChild().getString().isEmpty()); if (type == Token.GET) { // Get methods have no parameters. Preconditions.checkState(!first.getChildAtIndex(1).hasChildren()); add("get "); } else { // Set methods have one parameter. Preconditions.checkState(first.getChildAtIndex(1).hasOneChild()); add("set "); } // The name is on the GET or SET node. String name = n.getString(); Node fn = first; Node parameters = fn.getChildAtIndex(1); Node body = fn.getLastChild(); // Add the property name. if (!n.isQuotedString() && TokenStream.isJSIdentifier(name) && // do not encode literally any non-literal characters that were // unicode escaped. NodeUtil.isLatin(name)) { add(name); } else { // Determine if the string is a simple number. double d = getSimpleNumber(name); if (!Double.isNaN(d)) { cc.addNumber

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS>(d); } else { add(jsString(n.getString(), outputCharsetEncoder)); } } add(parameters); add(body, Context.PRESERVE_BLOCK); break; case Token.SCRIPT: case Token.BLOCK: { if (n.getClass() != Node.class) { throw new Error("Unexpected Node subclass."); } boolean preserveBlock = context == Context.PRESERVE_BLOCK; if (preserveBlock) { cc.beginBlock(); } boolean preferLineBreaks = type == Token.SCRIPT || (type == Token.BLOCK && !preserveBlock && n.getParent() != null && n.getParent().getType() == Token.SCRIPT); for (Node c = first; c != null; c = c.getNext()) { add(c, Context.STATEMENT); // VAR doesn't include ';' since it gets used in expressions if (c.getType() == Token.VAR) { cc.endStatement(); } if (c.getType() == Token.FUNCTION) { cc.maybeLineBreak(); } // Prefer to break lines in between top-level statements // because top level statements are more homogeneous. if (preferLineBreaks) { cc.notePreferredLineBreak(); } } if (preserveBlock) { cc.endBlock(cc.breakAfterBlockFor(n, context == Context.STATEMENT)); } break; } case Token.FOR: if (childCount == 4) { add("for("); if (first.getType() == Token.VAR) { add(first, Context.IN_FOR_INIT_CLAUSE); } else { addExpr(first, 0, Context.IN_FOR_INIT_CLAUSE); } add(";"); add(first.getNext()); add(";"); add(first.getNext().getNext()); add(")"); addNonEmptyStatement( last, getContextForNonEmptyExpression(context), false); } else { Preconditions.checkState(childCount == 3); add("for("); add(first); add("in"); add(first.getNext()); add(")"); addNonEmptyStatement( last, getContextForNonEmptyExpression(context), false);

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS> } break; case Token.DO: Preconditions.checkState(childCount == 2); add("do"); addNonEmptyStatement(first, Context.OTHER, false); add("while("); add(last); add(")"); cc.endStatement(); break; case Token.WHILE: Preconditions.checkState(childCount == 2); add("while("); add(first); add(")"); addNonEmptyStatement( last, getContextForNonEmptyExpression(context), false); break; case Token.EMPTY: Preconditions.checkState(childCount == 0); break; case Token.GETPROP: { Preconditions.checkState( childCount == 2, "Bad GETPROP: expected 2 children, but got %s", childCount); Preconditions.checkState( last.getType() == Token.STRING, "Bad GETPROP: RHS should be STRING"); boolean needsParens = (first.getType() == Token.NUMBER); if (needsParens) { add("("); } addLeftExpr(first, NodeUtil.precedence(type), context); if (needsParens) { add(")"); } add("."); addIdentifier(last.getString()); break; } case Token.GETELEM: Preconditions.checkState( childCount == 2, "Bad GETELEM: expected 2 children but got %s", childCount); addLeftExpr(first, NodeUtil.precedence(type), context); add("["); add(first.getNext()); add("]"); break; case Token.WITH: Preconditions.checkState(childCount == 2); add("with("); add(first); add(")"); addNonEmptyStatement( last, getContextForNonEmptyExpression(context), false); break; case Token.INC: case Token.DEC: { Preconditions.checkState(childCount == 1); String o = type == Token.INC ? "++" : "--"; int postProp = n.getIntProp(Node.INCRDECR_PROP); // A non-zero post-prop value indicates a post inc/dec, default of zero // is a pre-inc/dec. if (post

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS>Prop != 0) { addLeftExpr(first, NodeUtil.precedence(type), context); cc.addOp(o, false); } else { cc.addOp(o, false); add(first); } break; } case Token.CALL: // We have two special cases here: // 1) If the left hand side of the call is a direct reference to eval, // then it must have a DIRECT_EVAL annotation. If it does not, then // that means it was originally an indirect call to eval, and that // indirectness must be preserved. // 2) If the left hand side of the call is a property reference, // then the call must not a FREE_CALL annotation. If it does, then // that means it was originally an call without an explicit this and // that must be preserved. if (isIndirectEval(first) || n.getBooleanProp(Node.FREE_CALL) && NodeUtil.isGet(first)) { add("(0,"); addExpr(first, NodeUtil.precedence(Token.COMMA)); add(")"); } else { addLeftExpr(first, NodeUtil.precedence(type), context); } add("("); addList(first.getNext()); add(")"); break; case Token.IF: boolean hasElse = childCount == 3; boolean ambiguousElseClause = context == Context.BEFORE_DANGLING_ELSE && !hasElse; if (ambiguousElseClause) { cc.beginBlock(); } add("if("); add(first); add(")"); if (hasElse) { addNonEmptyStatement( first.getNext(), Context.BEFORE_DANGLING_ELSE, false); add("else"); addNonEmptyStatement( last, getContextForNonEmptyExpression(context), false); } else { addNonEmptyStatement(first.getNext(), Context.OTHER, false); Preconditions.checkState(childCount == 2); } if (ambiguousElseClause) { cc.endBlock(); } break; case Token.NULL: case Token.THIS: case Token.FALSE: case Token.TRUE: Preconditions.checkState(childCount == 0); add

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS>(Node.tokenToName(type)); break; case Token.CONTINUE: Preconditions.checkState(childCount <= 1); add("continue"); if (childCount == 1) { if (first.getType() != Token.LABEL_NAME) { throw new Error("Unexpected token type. Should be LABEL_NAME."); } add(" "); add(first); } cc.endStatement(); break; case Token.DEBUGGER: Preconditions.checkState(childCount == 0); add("debugger"); cc.endStatement(); break; case Token.BREAK: Preconditions.checkState(childCount <= 1); add("break"); if (childCount == 1) { if (first.getType() != Token.LABEL_NAME) { throw new Error("Unexpected token type. Should be LABEL_NAME."); } add(" "); add(first); } cc.endStatement(); break; case Token.EXPR_VOID: throw new Error("Unexpected EXPR_VOID. Should be EXPR_RESULT."); case Token.EXPR_RESULT: Preconditions.checkState(childCount == 1); add(first, Context.START_OF_EXPR); cc.endStatement(); break; case Token.NEW: add("new "); int precedence = NodeUtil.precedence(type); // If the first child contains a CALL, then claim higher precedence // to force parentheses. Otherwise, when parsed, NEW will bind to the // first viable parentheses (don't traverse into functions). if (NodeUtil.containsType(first, Token.CALL, new MatchNotFunction())) { precedence = NodeUtil.precedence(first.getType()) + 1; } addExpr(first, precedence); // '()' is optional when no arguments are present Node next = first.getNext(); if (next != null) { add("("); addList(next); add(")"); } break; case Token.STRING: if (childCount != ((n.getParent() != null && n.getParent().getType() == Token.OBJECTLIT) ? 1 : 0)) { throw new IllegalStateException( "Unexpected String children: " + n.getParent().toStringTree()); } add(jsString

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS> (first.getType() != Token.LABEL_NAME) { throw new Error("Unexpected token type. Should be LABEL_NAME."); } add(first); add(":"); addNonEmptyStatement( last, getContextForNonEmptyExpression(context), true); break; // This node is auto generated in anonymous functions and should just get // ignored for our purposes. case Token.SETNAME: break; default: throw new Error("Unknown type " + type + "\n" + n.toStringTree()); } cc.endSourceMapping(n); } static boolean isSimpleNumber(String s) { int len = s.length(); for (int index = 0; index < len; index++) { char c = s.charAt(index); if (c < '0' || c > '9') { return false; } } return len > 0; } static double getSimpleNumber(String s) { if (isSimpleNumber(s)) { long l = Long.parseLong(s); if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) { return l; } } return Double.NaN; } /** * @return Whether the name is an indirect eval. */ private boolean isIndirectEval(Node n) { return n.getType() == Token.NAME && "eval".equals(n.getString()) && !n.getBooleanProp(Node.DIRECT_EVAL); } /** * Adds a block or expression, substituting a VOID with an empty statement. * This is used for "for (...);" and "if (...);" type statements. * * @param n The node to print. * @param context The context to determine how the node should be printed. */ private void addNonEmptyStatement( Node n, Context context, boolean allowNonBlockChild) { Node nodeToProcess = n; if (!allowNonBlockChild && n.getType() != Token.BLOCK) { throw new Error("Missing BLOCK child."); } // Strip unneeded blocks, that is blocks with <2 children unless // the CodePrinter specifically wants to keep them. if (n.getType() == Token.BLOCK) { int count = getNonEmptyChildCount(n, 2);

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS> return true; } @Override public ObjectType getImplicitPrototype() { return registry.getNativeObjectType(JSTypeNative.OBJECT_TYPE); } @Override boolean defineProperty(String propertyName, JSType type, boolean inferred, boolean inExterns, Node propertyNode) { if (isFrozen) { return false; } if (!inferred) { properties.put(propertyName, type); } return super.defineProperty(propertyName, type, inferred, inExterns, propertyNode); } @Override public JSType getLeastSupertype(JSType that) { if (!that.isRecordType()) { return super.getLeastSupertype(that); } RecordType thatRecord = (RecordType) that; RecordTypeBuilder builder = new RecordTypeBuilder(registry); // The least supertype consist of those properties of the record // type that both record types hold in common both by name and // type of the properties themselves. for (String property : properties.keySet()) { if (thatRecord.hasProperty(property) && thatRecord.getPropertyType(property).isEquivalentTo( getPropertyType(property))) { builder.addProperty(property, getPropertyType(property), getPropertyNode(property)); } } return builder.build(); } @Override public JSType getGreatestSubtype(JSType that) { if (that.isRecordType()) { RecordType thatRecord = (RecordType) that; RecordTypeBuilder builder = new RecordTypeBuilder(registry); // The greatest subtype consists of those *unique* properties of both // record types. If any property conflicts, then the NO_TYPE type // is returned. for (String property : properties.keySet()) { if (thatRecord.hasProperty(property) && !thatRecord.getPropertyType(property).isEquivalentTo( getPropertyType(property))) { return registry.getNativeObjectType(JSTypeNative.NO_TYPE); } builder.addProperty(property, getPropertyType(property), getPropertyNode(property)); } for (String property : thatRecord.properties.keySet()) { if (!hasProperty(property)) { builder.addProperty(property, thatRecord.getPropertyType(property), thatRecord.getPropertyNode(property)); } }

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS>> scope) { for (Map.Entry<String, JSType> entry : properties.entrySet()) { JSType type = entry.getValue(); JSType resolvedType = type.resolve(t, scope); if (type != resolvedType) { properties.put(entry.getKey(), resolvedType); } } return super.resolveInternal(t, scope); } }

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS>/* * Copyright 2008 The Closure Compiler Authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp.graph; import java.util.Collection; /** * A minimal graph interface. Provided is add nodes to the graph, adjacency * calculation between a SubGraph and a GraphNode, and adding node annotations. * * <p>For a more extensive interface, see {@link Graph}. * * * @param <N> Value type that the graph node stores. * @param <E> Value type that the graph edge stores. * @see Graph */ public interface AdjacencyGraph<N, E> { /** Gets an immutable list of all nodes. */ Collection<GraphNode<N, E>> getNodes(); /** * Gets a node from the graph given a value. Values equality are compared * using <code>Object.equals</code>. * * @param value The node's value. * @return The corresponding node in the graph, null if there value has no * corresponding node. */ GraphNode<N, E> getNode(N value); /** Returns an empty SubGraph for this Graph. */ SubGraph<N, E> newSubGraph(); /** Makes each node's annotation null. */ void clearNodeAnnotations(); /** * Returns a weight for the given value to be used in ordering nodes, e.g. * in {@link GraphColoring}. */ int getWeight(N value); }

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS> greatest type (top) and is never a subtype of * another except itself or the Unknown type or a named alias. * @return {@code this.isEquivalentTo(that)} */ @Override public boolean isSubtype(JSType that) { return JSType.isSubtype(this, that); } @Override public boolean isAllType() { return true; } @Override public boolean matchesStringContext() { // Be lenient. return true; } @Override public boolean matchesObjectContext() { // Be lenient. return true; } @Override public boolean canBeCalled() { return false; } @Override public TernaryValue testForEquality(JSType that) { return UNKNOWN; } @Override public String toString() { return "*"; } @Override public String getDisplayName() { return "<Any Type>"; } @Override public boolean hasDisplayName() { return true; } @Override public <T> T visit(Visitor<T> visitor) { return visitor.caseAllType(); } @Override public BooleanLiteralSet getPossibleToBooleanOutcomes() { return BooleanLiteralSet.BOTH; } @Override JSType resolveInternal(ErrorReporter t, StaticScope<JSType> scope) { return this; } }

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS> "tweak ID contains illegal characters. Only letters, numbers, _ " + "and . are allowed"); /** * An enum of goog.tweak functions. */ private static enum TweakFunction { REGISTER_BOOLEAN("goog.tweak.registerBoolean", "boolean", Token.TRUE, Token.FALSE), REGISTER_NUMBER("goog.tweak.registerNumber", "number", Token.NUMBER), REGISTER_STRING("goog.tweak.registerString", "string", Token.STRING), OVERRIDE_DEFAULT_VALUE("goog.tweak.overrideDefaultValue"), GET_COMPILER_OVERRIDES("goog.tweak.getCompilerOverrides_"), GET_BOOLEAN("goog.tweak.getBoolean", REGISTER_BOOLEAN), GET_NUMBER("goog.tweak.getNumber", REGISTER_NUMBER), GET_STRING("goog.tweak.getString", REGISTER_STRING); final String name; final String expectedTypeName; final int validNodeTypeA; final int validNodeTypeB; final TweakFunction registerFunction; TweakFunction(String name) { this(name, null, Token.ERROR, Token.ERROR, null); } TweakFunction(String name, String expectedTypeName, int validNodeTypeA) { this(name, expectedTypeName, validNodeTypeA, Token.ERROR, null); } TweakFunction(String name, String expectedTypeName, int validNodeTypeA, int validNodeTypeB) { this(name, expectedTypeName, validNodeTypeA, validNodeTypeB, null); } TweakFunction(String name, TweakFunction registerFunction) { this(name, null, Token.ERROR, Token.ERROR, registerFunction); } TweakFunction(String name, String expectedTypeName, int validNodeTypeA, int validNodeTypeB, TweakFunction registerFunction) { this.name = name; this.expectedTypeName = expectedTypeName; this.validNodeTypeA = validNodeTypeA; this.validNodeTypeB = validNodeTypeB; this.registerFunction = registerFunction; } boolean isValidNodeType(int type) { return type == validNodeTypeA || type == validNodeTypeB; } boolean isCorrectRegisterFunction(TweakFunction registerFunction) { Preconditions.checkNotNull(registerFunction); return this.registerFunction == registerFunction; } boolean isGetterFunction

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS>String, TweakInfo> tweakInfos) { for (Entry<String, Node> entry : compilerDefaultValueOverrides.entrySet()) { String tweakId = entry.getKey(); TweakInfo tweakInfo = tweakInfos.get(tweakId); if (tweakInfo == null) { compiler.report(JSError.make(UNKNOWN_TWEAK_WARNING, tweakId)); } else { TweakFunction registerFunc = tweakInfo.registerCall.tweakFunc; Node value = entry.getValue(); if (!registerFunc.isValidNodeType(value.getType())) { compiler.report(JSError.make(INVALID_TWEAK_DEFAULT_VALUE_WARNING, tweakId, registerFunc.getName(), registerFunc.getExpectedTypeName())); } else { tweakInfo.defaultValueNode = value; } } } } /** * Finds all calls to goog.tweak functions and emits warnings/errors if any * of the calls have issues. * @return A map of {@link TweakInfo} structures, keyed by tweak ID. */ private CollectTweaksResult collectTweaks(Node root) { CollectTweaks pass = new CollectTweaks(); NodeTraversal.traverse(compiler, root, pass); Map<String, TweakInfo> tweakInfos = pass.allTweaks; for (TweakInfo tweakInfo: tweakInfos.values()) { tweakInfo.emitAllWarnings(); } return new CollectTweaksResult(tweakInfos, pass.getOverridesCalls); } private final static class CollectTweaksResult { final Map<String, TweakInfo> tweakInfos; final List<TweakFunctionCall> getOverridesCalls; CollectTweaksResult(Map<String, TweakInfo> tweakInfos, List<TweakFunctionCall> getOverridesCalls) { this.tweakInfos = tweakInfos; this.getOverridesCalls = getOverridesCalls; } } /** * Processes all calls to goog.tweak functions. */ private final class CollectTweaks extends AbstractPostOrderCallback { final Map<String, TweakInfo> allTweaks = Maps.newHashMap(); final List<TweakFunctionCall> getOverridesCalls = Lists.newArrayList(); @Override public void visit(NodeTraversal t, Node n,

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS> information should be generated. * <p> * Without source information, evaluating the "toString" method * on JavaScript functions produces only "[native code]" for * the body of the function. * Note that code generated without source is not fully ECMA * conformant. * @since 1.3 */ public final void setGeneratingSource(boolean generatingSource) { if (sealed) onSealedMutation(); this.generatingSource = generatingSource; } /** * Get the current optimization level. * <p> * The optimization level is expressed as an integer between -1 and * 9. * @since 1.3 * */ public final int getOptimizationLevel() { return optimizationLevel; } public static boolean isValidOptimizationLevel(int optimizationLevel) { return -1 <= optimizationLevel && optimizationLevel <= 9; } public static void checkOptimizationLevel(int optimizationLevel) { if (isValidOptimizationLevel(optimizationLevel)) { return; } throw new IllegalArgumentException( "Optimization level outside [-1..9]: "+optimizationLevel); } /** * Get a value corresponding to a key. * <p> * Since the Context is associated with a thread it can be * used to maintain values that can be later retrieved using * the current thread. * <p> * Note that the values are maintained with the Context, so * if the Context is disassociated from the thread the values * cannot be retreived. Also, if private data is to be maintained * in this manner the key should be a java.lang.Object * whose reference is not divulged to untrusted code. * @param key the key used to lookup the value * @return a value previously stored using putThreadLocal. */ public final Object getThreadLocal(Object key) { if (hashtable == null) return null; return hashtable.get(key); } /** * Put a value that can later be retrieved using a given key. * <p> * @param key the key used to index the value * @param value the value to save */ public final void putThreadLocal(Object key, Object value) { if (sealed) onSealedMutation(); if (hashtable

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS> == null) hashtable = new Hashtable<Object, Object>(); hashtable.put(key, value); } /** * Remove values from thread-local storage. * @param key the key for the entry to remove. * @since 1.5 release 2 */ public final void removeThreadLocal(Object key) { if (sealed) onSealedMutation(); if (hashtable == null) return; hashtable.remove(key); } /** * @deprecated * @see #FEATURE_DYNAMIC_SCOPE * @see #hasFeature(int) */ @Deprecated public final boolean hasCompileFunctionsWithDynamicScope() { return compileFunctionsWithDynamicScopeFlag; } /** * @deprecated * @see #FEATURE_DYNAMIC_SCOPE * @see #hasFeature(int) */ @Deprecated public final void setCompileFunctionsWithDynamicScope(boolean flag) { if (sealed) onSealedMutation(); compileFunctionsWithDynamicScopeFlag = flag; } /** * Return the debugger context data associated with current context. * @return the debugger data, or null if debugger is not attached */ public final Object getDebuggerContextData() { return debuggerData; } /** * Implementation of {@link Context#hasFeature(int featureIndex)}. * This can be used to customize {@link Context} without introducing * additional subclasses. */ protected boolean hasFeature(int featureIndex) { int version; switch (featureIndex) { case Context.FEATURE_NON_ECMA_GET_YEAR: /* * During the great date rewrite of 1.3, we tried to track the * evolving ECMA standard, which then had a definition of * getYear which always subtracted 1900. Which we * implemented, not realizing that it was incompatible with * the old behavior... now, rather than thrash the behavior * yet again, we've decided to leave it with the - 1900 * behavior and point people to the getFullYear method. But * we try to protect existing scripts that have specified a * version... */ version = getLanguageVersion(); return (version == Context.VERSION_1_0 || version == Context

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS>TAG_EMPTY", "Could not resolve type in {0} tag of {1}"); static final DiagnosticType IMPLEMENTS_WITHOUT_CONSTRUCTOR = DiagnosticType.warning( "JSC_IMPLEMENTS_WITHOUT_CONSTRUCTOR", "@implements used without @constructor or @interface for {0}"); static final DiagnosticType VAR_ARGS_MUST_BE_LAST = DiagnosticType.warning( "JSC_VAR_ARGS_MUST_BE_LAST", "variable length argument must be last"); static final DiagnosticType OPTIONAL_ARG_AT_END = DiagnosticType.warning( "JSC_OPTIONAL_ARG_AT_END", "optional arguments must be at the end"); static final DiagnosticType INEXISTANT_PARAM = DiagnosticType.warning( "JSC_INEXISTANT_PARAM", "parameter {0} does not appear in {1}''s parameter list"); static final DiagnosticType TYPE_REDEFINITION = DiagnosticType.warning( "JSC_TYPE_REDEFINITION", "attempted re-definition of type {0}\n" + "found : {1}\n" + "expected: {2}"); static final DiagnosticType TEMPLATE_TYPE_DUPLICATED = DiagnosticType.error( "JSC_TEMPLATE_TYPE_DUPLICATED", "Only one parameter type must be the template type"); static final DiagnosticType TEMPLATE_TYPE_EXPECTED = DiagnosticType.error( "JSC_TEMPLATE_TYPE_EXPECTED", "The template type must be a parameter type"); static final DiagnosticType THIS_TYPE_NON_OBJECT = DiagnosticType.warning( "JSC_THIS_TYPE_NON_OBJECT", "@this type of a function must be an object\n" + "Actual type: {0}"); private class ExtendedTypeValidator implements Predicate<JSType> { @Override public boolean apply(JSType type) { ObjectType objectType = ObjectType.cast(type); if (objectType == null) { reportWarning(EXTENDS_NON_OBJECT, fnName, type.toString()); } else if ( objectType.isEmptyType() || (objectType.isUnknownType() && // If this has a supertype that hasn't been resolved yet, // then we can assume this type will be ok once the super // type resolves. (object

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS>Type.getImplicitPrototype() == null || objectType.getImplicitPrototype().isResolved()))) { reportWarning(RESOLVED_TAG_EMPTY, "@extends", fnName); } else { return true; } return false; } } private class ImplementedTypeValidator implements Predicate<JSType> { @Override public boolean apply(JSType type) { ObjectType objectType = ObjectType.cast(type); if (objectType == null) { reportError(BAD_IMPLEMENTED_TYPE, fnName); } else if ( objectType.isEmptyType() || (objectType.isUnknownType() && // If this has a supertype that hasn't been resolved yet, // then we can assume this type will be ok once the super // type resolves. (objectType.getImplicitPrototype() == null || objectType.getImplicitPrototype().isResolved()))) { reportWarning(RESOLVED_TAG_EMPTY, "@implements", fnName); } else { return true; } return false; } } private class ThisTypeValidator implements Predicate<JSType> { @Override public boolean apply(JSType type) { // TODO(user): Doing an instanceof check here is too // restrictive as (Date,Error) is, for instance, an object type // even though its implementation is a UnionType. Would need to // create interfaces JSType, ObjectType, FunctionType etc and have // separate implementation instead of the class hierarchy, so that // union types can also be object types, etc. if (!type.restrictByNotNullOrUndefined().isSubtype( typeRegistry.getNativeType(OBJECT_TYPE))) { reportWarning(THIS_TYPE_NON_OBJECT, type.toString()); return false; } return true; } } /** * @param fnName The function name. * @param compiler The compiler. * @param errorRoot The node to associate with any warning generated by * this builder. * @param sourceName A source name for associating any warnings that * we have to emit. * @param scope The syntactic scope. */ FunctionTypeBuilder(String fnName, AbstractCompiler compiler, Node errorRoot, String sourceName, Scope scope) { Preconditions.checkNotNull(errorRoot); this.fnName

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS>(VOID_TYPE); returnTypeInferred = true; } } return this; } /** * Infer the role of the function (whether it's a constructor or interface) * and what it inherits from in JSDocInfo. */ FunctionTypeBuilder inferInheritance(@Nullable JSDocInfo info) { if (info != null) { isConstructor = info.isConstructor(); isInterface = info.isInterface(); // base type if (info.hasBaseType()) { if (isConstructor || isInterface) { JSType maybeBaseType = info.getBaseType().evaluate(scope, typeRegistry); if (maybeBaseType != null && maybeBaseType.setValidator(new ExtendedTypeValidator())) { baseType = (ObjectType) maybeBaseType; } } else { reportWarning(EXTENDS_WITHOUT_TYPEDEF, fnName); } } // implemented interfaces if (isConstructor || isInterface) { implementedInterfaces = Lists.newArrayList(); for (JSTypeExpression t : info.getImplementedInterfaces()) { JSType maybeInterType = t.evaluate(scope, typeRegistry); if (maybeInterType != null && maybeInterType.setValidator(new ImplementedTypeValidator())) { implementedInterfaces.add((ObjectType) maybeInterType); } } if (baseType != null) { JSType maybeFunctionType = baseType.getConstructor(); if (maybeFunctionType instanceof FunctionType) { FunctionType functionType = baseType.getConstructor(); Iterables.addAll( implementedInterfaces, functionType.getImplementedInterfaces()); } } } else if (info.getImplementedInterfaceCount() > 0) { reportWarning(IMPLEMENTS_WITHOUT_CONSTRUCTOR, fnName); } } return this; } /** * Infers the type of {@code this}. * @param type The type of this. */ FunctionTypeBuilder inferThisType(JSDocInfo info, JSType type) { // Look at the @this annotation first. inferThisType(info, (Node) null); if (thisType == null) { ObjectType objType = ObjectType.cast(type); if (objType != null && (info == null || !info.hasType())) { thisType = objType; } }

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS> ref); } } } } } private void reportBadModuleReference(Name name, Ref ref) { compiler.report( JSError.make(ref.sourceName, ref.node, STRICT_MODULE_DEP_QNAME, ref.module.getName(), name.declaration.module.getName(), name.fullName())); } private void reportRefToUndefinedName(Name name, Ref ref) { // grab the highest undefined ancestor to output in the warning message. while (name.parent != null && name.parent.globalSets + name.parent.localSets == 0) { name = name.parent; } // If this is an annotated EXPR-GET, don't do anything. Node parent = ref.node.getParent(); if (parent.getType() == Token.EXPR_RESULT) { JSDocInfo info = ref.node.getJSDocInfo(); if (info != null && info.hasTypedefType()) { return; } } compiler.report( JSError.make(ref.sourceName, ref.node, level, UNDEFINED_NAME_WARNING, name.fullName())); } /** * Checks whether the given name is a property, and whether that property * must be initialized with its full qualified name. */ private static boolean propertyMustBeInitializedByFullName(Name name) { // If an object literal in the global namespace is never aliased, // then all of its properties must be defined using its full qualified // name. This implies that its properties must all be in the global // namespace as well. // // The same is not true for FUNCTION and OTHER types, because their // implicit prototypes have properties that are not captured by the global // namespace. return name.parent != null && name.parent.aliasingGets == 0 && name.parent.type == Name.Type.OBJECTLIT; } }

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS>/* * Copyright 2007 The Closure Compiler Authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableList; import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.jstype.FunctionType; import com.google.javascript.rhino.jstype.JSTypeNative; import com.google.javascript.rhino.jstype.ObjectType; import java.util.Collection; import java.util.List; import java.util.Set; /** * This describes the Closure-specific JavaScript coding conventions. * */ public class ClosureCodingConvention extends DefaultCodingConvention { private static final long serialVersionUID = 1L; private static final String TYPEDEF_NAME = "goog.typedef"; static final DiagnosticType OBJECTLIT_EXPECTED = DiagnosticType.warning( "JSC_REFLECT_OBJECTLIT_EXPECTED", "Object literal expected as second argument"); /** * Closure's goog.inherits adds a {@code superClass_} property to the * subclass, and a {@code constructor} property. */ @Override public void applySubclassRelationship(FunctionType parentCtor, FunctionType childCtor, SubclassType type) { if (type == SubclassType.INHERITS) { childCtor.defineDeclaredProperty("superClass_", parentCtor.getPrototype(), false, parentCtor.getSource()); childCtor.getPrototype().defineDeclaredProperty("constructor", childCtor

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS>, false, parentCtor.getSource()); } } /** * {@inheritDoc} * * <p>Understands several different inheritance patterns that occur in * Google code (various uses of {@code inherits} and {@code mixin}). */ @Override public SubclassRelationship getClassesDefinedByCall(Node callNode) { Node callName = callNode.getFirstChild(); SubclassType type = typeofClassDefiningName(callName); if (type != null) { Node subclass = null; Node superclass = callNode.getLastChild(); // There are six possible syntaxes for a class-defining method: // SubClass.inherits(SuperClass) // goog.inherits(SubClass, SuperClass) // goog$inherits(SubClass, SuperClass) // SubClass.mixin(SuperClass.prototype) // goog.mixin(SubClass.prototype, SuperClass.prototype) // goog$mixin(SubClass.prototype, SuperClass.prototype) boolean isDeprecatedCall = callNode.getChildCount() == 2 && callName.getType() == Token.GETPROP; if (isDeprecatedCall) { // SubClass.inherits(SuperClass) subclass = callName.getFirstChild(); } else if (callNode.getChildCount() == 3) { // goog.inherits(SubClass, SuperClass) subclass = callName.getNext(); } if (type == SubclassType.MIXIN) { // Only consider mixins that mix two prototypes as related to // inheritance. if (!endsWithPrototype(superclass)) { return null; } if (!isDeprecatedCall) { if (!endsWithPrototype(subclass)) { return null; } // Strip off the prototype from the name. subclass = subclass.getFirstChild(); } superclass = superclass.getFirstChild(); } // bail out if either of the side of the "inherits" // isn't a real class name. This prevents us from // doing something weird in cases like: // goog.inherits(MySubClass, cond ? SuperClass1 : BaseClass2) if (subclass != null && subclass.isUnscopedQualifiedName() && superclass.isUnscopedQualifiedName()) { return new SubclassRelationship(type, subclass, superclass); } } return null;

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS> String functionName){ String className = null; if (NodeUtil.isExprCall(parent)) { Node callee = node.getFirstChild(); if (callee != null && callee.getType() == Token.GETPROP) { String qualifiedName = callee.getQualifiedName(); if ((functionName).equals(qualifiedName)) { className = callee.getNext().getString(); } } } return className; } /** * Use closure's implementation. * @return closure's function name for exporting properties. */ @Override public String getExportPropertyFunction() { return "goog.exportProperty"; } /** * Use closure's implementation. * @return closure's function name for exporting symbols. */ @Override public String getExportSymbolFunction() { return "goog.exportSymbol"; } @Override public List<String> identifyTypeDeclarationCall(Node n) { Node callName = n.getFirstChild(); if ("goog.addDependency".equals(callName.getQualifiedName()) && n.getChildCount() >= 3) { Node typeArray = callName.getNext().getNext(); if (typeArray.getType() == Token.ARRAYLIT) { List<String> typeNames = Lists.newArrayList(); for (Node name = typeArray.getFirstChild(); name != null; name = name.getNext()) { if (name.getType() == Token.STRING) { typeNames.add(name.getString()); } } return typeNames; } } return null; } @Override public String identifyTypeDefAssign(Node n) { Node firstChild = n.getFirstChild(); int type = n.getType(); if (type == Token.ASSIGN) { if (TYPEDEF_NAME.equals(n.getLastChild().getQualifiedName())) { return firstChild.getQualifiedName(); } } else if (type == Token.VAR && firstChild.hasChildren()) { if (TYPEDEF_NAME.equals( firstChild.getFirstChild().getQualifiedName())) { return firstChild.getString(); } } return null; } @Override public String getAbstractMethodName() { return "goog.abstractMethod"; } @Override public String getSingletonGetterClassName(Node callNode) { Node

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS> extends Node { private static final long serialVersionUID = 1L; NumberNode(double number) { super(Token.NUMBER); this.number = number; } public NumberNode(double number, int lineno, int charno) { super(Token.NUMBER, lineno, charno); this.number = number; } @Override public double getDouble() { return this.number; } @Override public void setDouble(double d) { this.number = d; } @Override boolean isEquivalentTo(Node node, boolean compareJsType, boolean recurse) { return (super.isEquivalentTo(node, compareJsType, recurse) && getDouble() == ((NumberNode) node).getDouble()); } private double number; } private static class StringNode extends Node { private static final long serialVersionUID = 1L; StringNode(int type, String str) { super(type); if (null == str) { throw new IllegalArgumentException("StringNode: str is null"); } this.str = str; } StringNode(int type, String str, int lineno, int charno) { super(type, lineno, charno); if (null == str) { throw new IllegalArgumentException("StringNode: str is null"); } this.str = str; } /** * returns the string content. * @return non null. */ @Override public String getString() { return this.str; } /** * sets the string content. * @param str the new value. Non null. */ @Override public void setString(String str) { if (null == str) { throw new IllegalArgumentException("StringNode: str is null"); } this.str = str; } @Override boolean isEquivalentTo(Node node, boolean compareJsType, boolean recurse) { return (super.isEquivalentTo(node, compareJsType, recurse) && this.str.equals(((StringNode) node).str)); } /** * If the property is not defined, this was not a quoted key. The * QUOTED_PROP int property is only assigned to STRING tokens used as * object lit keys. * @return true if this was a quoted

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS> string key in an object literal. */ @Override public boolean isQuotedString() { return getBooleanProp(QUOTED_PROP); } /** * This should only be called for STRING nodes created in object lits. */ @Override public void setQuotedString() { putBooleanProp(QUOTED_PROP, true); } private String str; } // PropListItems are immutable so that they can be shared. private static class PropListItem implements Serializable { private static final long serialVersionUID = 1L; final PropListItem next; final int type; final int intValue; final Object objectValue; PropListItem(int type, int intValue, PropListItem next) { this(type, intValue, null, next); } PropListItem(int type, Object objectValue, PropListItem next) { this(type, 0, objectValue, next); } PropListItem( int type, int intValue, Object objectValue, PropListItem next) { this.type = type; this.intValue = intValue; this.objectValue = objectValue; this.next = next; } } public Node(int nodeType) { type = nodeType; parent = null; sourcePosition = -1; } public Node(int nodeType, Node child) { Preconditions.checkArgument(child.parent == null, "new child has existing parent"); Preconditions.checkArgument(child.next == null, "new child has existing sibling"); type = nodeType; parent = null; first = last = child; child.next = null; child.parent = this; sourcePosition = -1; } public Node(int nodeType, Node left, Node right) { Preconditions.checkArgument(left.parent == null, "first new child has existing parent"); Preconditions.checkArgument(left.next == null, "first new child has existing sibling"); Preconditions.checkArgument(right.parent == null, "second new child has existing parent"); Preconditions.checkArgument(right.next == null, "second new child has existing sibling"); type = nodeType; parent = null; first = left; last = right; left.next = right; left.parent =

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS> this; right.next = null; right.parent = this; sourcePosition = -1; } public Node(int nodeType, Node left, Node mid, Node right) { Preconditions.checkArgument(left.parent == null); Preconditions.checkArgument(left.next == null); Preconditions.checkArgument(mid.parent == null); Preconditions.checkArgument(mid.next == null); Preconditions.checkArgument(right.parent == null); Preconditions.checkArgument(right.next == null); type = nodeType; parent = null; first = left; last = right; left.next = mid; left.parent = this; mid.next = right; mid.parent = this; right.next = null; right.parent = this; sourcePosition = -1; } public Node(int nodeType, Node left, Node mid, Node mid2, Node right) { Preconditions.checkArgument(left.parent == null); Preconditions.checkArgument(left.next == null); Preconditions.checkArgument(mid.parent == null); Preconditions.checkArgument(mid.next == null); Preconditions.checkArgument(mid2.parent == null); Preconditions.checkArgument(mid2.next == null); Preconditions.checkArgument(right.parent == null); Preconditions.checkArgument(right.next == null); type = nodeType; parent = null; first = left; last = right; left.next = mid; left.parent = this; mid.next = mid2; mid.parent = this; mid2.next = right; mid2.parent = this; right.next = null; right.parent = this; sourcePosition = -1; } public Node(int nodeType, int lineno, int charno) { type = nodeType; parent = null; sourcePosition = mergeLineCharNo(lineno, charno); } public Node(int nodeType, Node child, int lineno, int charno) { this(nodeType, child); sourcePosition = mergeLineCharNo(lineno, charno); } public Node(int nodeType, Node left, Node right, int lineno, int charno) { this(nodeType, left, right);

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS> sourcePosition = mergeLineCharNo(lineno, charno); } public Node(int nodeType, Node left, Node mid, Node right, int lineno, int charno) { this(nodeType, left, mid, right); sourcePosition = mergeLineCharNo(lineno, charno); } public Node(int nodeType, Node left, Node mid, Node mid2, Node right, int lineno, int charno) { this(nodeType, left, mid, mid2, right); sourcePosition = mergeLineCharNo(lineno, charno); } public Node(int nodeType, Node[] children, int lineno, int charno) { this(nodeType, children); sourcePosition = mergeLineCharNo(lineno, charno); } public Node(int nodeType, Node[] children) { this.type = nodeType; parent = null; if (children.length != 0) { this.first = children[0]; this.last = children[children.length - 1]; for (int i = 1; i < children.length; i++) { if (null != children[i - 1].next) { // fail early on loops. implies same node in array twice throw new IllegalArgumentException("duplicate child"); } children[i - 1].next = children[i]; Preconditions.checkArgument(children[i - 1].parent == null); children[i - 1].parent = this; } Preconditions.checkArgument(children[children.length - 1].parent == null); children[children.length - 1].parent = this; if (null != this.last.next) { // fail early on loops. implies same node in array twice throw new IllegalArgumentException("duplicate child"); } } } public static Node newNumber(double number) { return new NumberNode(number); } public static Node newNumber(double number, int lineno, int charno) { return new NumberNode(number, lineno, charno); } public static Node newString(String str) { return new StringNode(Token.STRING, str); } public static Node newString(int type, String str) { return new StringNode(type, str); } public static Node

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS> newString(String str, int lineno, int charno) { return new StringNode(Token.STRING, str, lineno, charno); } public static Node newString(int type, String str, int lineno, int charno) { return new StringNode(type, str, lineno, charno); } public int getType() { return type; } public void setType(int type) { this.type = type; } public boolean hasChildren() { return first != null; } public Node getFirstChild() { return first; } public Node getLastChild() { return last; } public Node getNext() { return next; } public Node getChildBefore(Node child) { if (child == first) { return null; } Node n = first; while (n.next != child) { n = n.next; if (n == null) { throw new RuntimeException("node is not a child"); } } return n; } public Node getChildAtIndex(int i) { Node n = first; while (i > 0) { n = n.next; i--; } return n; } public Node getLastSibling() { Node n = this; while (n.next != null) { n = n.next; } return n; } public void addChildToFront(Node child) { Preconditions.checkArgument(child.parent == null); Preconditions.checkArgument(child.next == null); child.parent = this; child.next = first; first = child; if (last == null) { last = child; } } public void addChildToBack(Node child) { Preconditions.checkArgument(child.parent == null); Preconditions.checkArgument(child.next == null); child.parent = this; child.next = null; if (last == null) { first = last = child; return; } last.next = child; last = child; } public void addChildrenToFront(Node children) { for (Node child = children; child != null; child = child.next) { Preconditions.checkArgument(child.parent == null

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS> } /** * Detaches child from Node and replaces it with newChild. */ public void replaceChild(Node child, Node newChild) { Preconditions.checkArgument(newChild.next == null, "The new child node has siblings."); Preconditions.checkArgument(newChild.parent == null, "The new child node already has a parent."); // Copy over important information. newChild.copyInformationFrom(child); newChild.next = child.next; newChild.parent = this; if (child == first) { first = newChild; } else { Node prev = getChildBefore(child); prev.next = newChild; } if (child == last) last = newChild; child.next = null; child.parent = null; } public void replaceChildAfter(Node prevChild, Node newChild) { Preconditions.checkArgument(prevChild.parent == this, "prev is not a child of this node."); Preconditions.checkArgument(newChild.next == null, "The new child node has siblings."); Preconditions.checkArgument(newChild.parent == null, "The new child node already has a parent."); // Copy over important information. newChild.copyInformationFrom(prevChild); Node child = prevChild.next; newChild.next = child.next; newChild.parent = this; prevChild.next = newChild; if (child == last) last = newChild; child.next = null; child.parent = null; } @VisibleForTesting PropListItem lookupProperty(int propType) { PropListItem x = propListHead; while (x != null && propType != x.type) { x = x.next; } return x; } /** * Clone the properties from the provided node without copying * the property object. The recieving node may not have any * existing properties. * @param other The node to clone properties from. * @return this node. */ public Node clonePropsFrom(Node other) { Preconditions.checkState(this.propListHead == null, "Node has existing properties."); this.propListHead = other.propListHead; return this; }

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS> public void removeProp(int propType) { PropListItem result = removeProp(propListHead, propType); if (result != propListHead) { propListHead = result; } } /** * @param item The item to inspect * @param propType The property to look for * @return The replacement list if the property was removed, or * 'item' otherwise. */ private PropListItem removeProp(PropListItem item, int propType) { if (item == null) { return null; } else if (item.type == propType) { return item.next; } else { PropListItem result = removeProp(item.next, propType); if (result != item.next) { return new PropListItem( item.type, item.intValue, item.objectValue, result); } else { return item; } } } public Object getProp(int propType) { PropListItem item = lookupProperty(propType); if (item == null) { return null; } return item.objectValue; } public boolean getBooleanProp(int propType) { return getIntProp(propType) != 0; } /** * Returns the integer value for the property, or 0 if the property * is not defined. */ public int getIntProp(int propType) { PropListItem item = lookupProperty(propType); if (item == null) { return 0; } return item.intValue; } public int getExistingIntProp(int propType) { PropListItem item = lookupProperty(propType); if (item == null) { Kit.codeBug(); } return item.intValue; } public void putProp(int propType, Object value) { removeProp(propType); if (value != null) { propListHead = new PropListItem(propType, value, propListHead); } } public void putBooleanProp(int propType, boolean value) { putIntProp(propType, value ? 1 : 0); } public void putIntProp(int propType, int value) { removeProp(propType); if (value != 0) { prop

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS>ListHead = new PropListItem(propType, value, propListHead); } } // Gets all the property types, in sorted order. private int[] getSortedPropTypes() { int count = 0; for (PropListItem x = propListHead; x != null; x = x.next) { count++; } int[] keys = new int[count]; for (PropListItem x = propListHead; x != null; x = x.next) { count--; keys[count] = x.type; } Arrays.sort(keys); return keys; } public int getLineno() { return extractLineno(sourcePosition); } public int getCharno() { return extractCharno(sourcePosition); } public int getSourcePosition() { return sourcePosition; } /** Can only be called when <tt>getType() == TokenStream.NUMBER</tt> */ public double getDouble() throws UnsupportedOperationException { if (this.getType() == Token.NUMBER) { throw new IllegalStateException( "Number node not created with Node.newNumber"); } else { throw new UnsupportedOperationException(this + " is not a number node"); } } /** Can only be called when <tt>getType() == TokenStream.NUMBER</tt> */ public void setDouble(double s) throws UnsupportedOperationException { if (this.getType() == Token.NUMBER) { throw new IllegalStateException( "Number node not created with Node.newNumber"); } else { throw new UnsupportedOperationException(this + " is not a string node"); } } /** Can only be called when node has String context. */ public String getString() throws UnsupportedOperationException { if (this.getType() == Token.STRING) { throw new IllegalStateException( "String node not created with Node.newString"); } else { throw new UnsupportedOperationException(this + " is not a string node"); } } /** Can only be called when node has String context. */ public void setString(String s) throws UnsupportedOperationException { if (this.getType() == Token.STRING) { throw new IllegalStateException( "String node not created with Node.newString"); } else { throw new UnsupportedOperationException(this + " is not a string node"); } } @Override public String toString()

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS> { return toString(true, true, true); } public String toString( boolean printSource, boolean printAnnotations, boolean printType) { if (Token.printTrees) { StringBuilder sb = new StringBuilder(); toString(sb, printSource, printAnnotations, printType); return sb.toString(); } return String.valueOf(type); } private void toString( StringBuilder sb, boolean printSource, boolean printAnnotations, boolean printType) { if (Token.printTrees) { sb.append(Token.name(type)); if (this instanceof StringNode) { sb.append(' '); sb.append(getString()); } else if (type == Token.FUNCTION) { sb.append(' '); // In the case of JsDoc trees, the first child is often not a string // which causes exceptions to be thrown when calling toString or // toStringTree. if (first == null || first.getType() != Token.NAME) { sb.append("<invalid>"); } else { sb.append(first.getString()); } } else if (this instanceof ScriptOrFnNode) { ScriptOrFnNode sof = (ScriptOrFnNode) this; if (this instanceof FunctionNode) { FunctionNode fn = (FunctionNode) this; sb.append(' '); sb.append(fn.getFunctionName()); } if (printSource) { sb.append(" [source name: "); sb.append(sof.getSourceName()); sb.append("] [encoded source length: "); sb.append(sof.getEncodedSourceEnd() - sof.getEncodedSourceStart()); sb.append("] [base line: "); sb.append(sof.getBaseLineno()); sb.append("] [end line: "); sb.append(sof.getEndLineno()); sb.append(']'); } } else if (type == Token.NUMBER) { sb.append(' '); sb.append(getDouble()); } if (printSource) { int lineno = getLineno(); if (lineno != -1) { sb.append(' '); sb.append(lineno); } } if (printAnnotations) { int[] keys = getSortedPropTypes(); for (int i = 0;

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS> i < keys.length; i++) { int type = keys[i]; PropListItem x = lookupProperty(type); sb.append(" ["); sb.append(propToString(type)); sb.append(": "); String value; switch (type) { case TARGETBLOCK_PROP: // can't add this as it recurses value = "target block property"; break; case LOCAL_BLOCK_PROP: // can't add this as it is dull value = "last local block"; break; case ISNUMBER_PROP: switch (x.intValue) { case BOTH: value = "both"; break; case RIGHT: value = "right"; break; case LEFT: value = "left"; break; default: throw Kit.codeBug(); } break; case SPECIALCALL_PROP: switch (x.intValue) { case SPECIALCALL_EVAL: value = "eval"; break; case SPECIALCALL_WITH: value = "with"; break; default: // NON_SPECIALCALL should not be stored throw Kit.codeBug(); } break; default: Object obj = x.objectValue; if (obj != null) { value = obj.toString(); } else { value = String.valueOf(x.intValue); } break; } sb.append(value); sb.append(']'); } } if (printType) { if (jsType != null) { String jsTypeString = jsType.toString(); if (jsTypeString != null) { sb.append(" : "); sb.append(jsTypeString); } } } } } public String toStringTree() { return toStringTreeImpl(); } private String toStringTreeImpl() { try { StringBuilder s = new StringBuilder(); appendStringTree(s); return s.toString(); } catch (IOException e) { throw new RuntimeException("Should not happen\n" + e); } } public void appendStringTree(Appendable appendable) throws IOException { toStringTreeHelper(this, 0, appendable); } private static void toStringTreeHelper(Node n, int level, Appendable sb) throws IOException { if (Token.

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS>printTrees) { for (int i = 0; i != level; ++i) { sb.append(" "); } sb.append(n.toString()); sb.append('\n'); for (Node cursor = n.getFirstChild(); cursor != null; cursor = cursor.getNext()) { toStringTreeHelper(cursor, level + 1, sb); } } } int type; // type of the node; Token.NAME for example Node next; // next sibling private Node first; // first element of a linked list of children private Node last; // last element of a linked list of children /** * Linked list of properties. Since vast majority of nodes would have * no more then 2 properties, linked list saves memory and provides * fast lookup. If this does not holds, propListHead can be replaced * by UintMap. */ private PropListItem propListHead; /** * COLUMN_BITS represents how many of the lower-order bits of * sourcePosition are reserved for storing the column number. * Bits above these store the line number. * This gives us decent position information for everything except * files already passed through a minimizer, where lines might * be longer than 4096 characters. */ public static final int COLUMN_BITS = 12; /** * MAX_COLUMN_NUMBER represents the maximum column number that can * be represented. JSCompiler's modifications to Rhino cause all * tokens located beyond the maximum column to MAX_COLUMN_NUMBER. */ public static final int MAX_COLUMN_NUMBER = (1 << COLUMN_BITS) - 1; /** * COLUMN_MASK stores a value where bits storing the column number * are set, and bits storing the line are not set. It's handy for * separating column number from line number. */ public static final int COLUMN_MASK = MAX_COLUMN_NUMBER; /** * Source position of this node. The position is encoded with the * column number in the low 12 bits of the integer, and the line * number in the rest. Create some handy constants so we can change this * size if we want. */ private int sourcePosition; private JSType jsType; private Node parent; //================================================================

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS> Token.ASSIGN_ADD: return "assign_add"; case Token.ASSIGN_SUB: return "assign_sub"; case Token.ASSIGN_MUL: return "assign_mul"; case Token.ASSIGN_DIV: return "assign_div"; case Token.ASSIGN_MOD: return "assign_mod"; case Token.HOOK: return "hook"; case Token.COLON: return "colon"; case Token.OR: return "or"; case Token.AND: return "and"; case Token.INC: return "inc"; case Token.DEC: return "dec"; case Token.DOT: return "dot"; case Token.FUNCTION: return "function"; case Token.EXPORT: return "export"; case Token.IMPORT: return "import"; case Token.IF: return "if"; case Token.ELSE: return "else"; case Token.SWITCH: return "switch"; case Token.CASE: return "case"; case Token.DEFAULT: return "default"; case Token.WHILE: return "while"; case Token.DO: return "do"; case Token.FOR: return "for"; case Token.BREAK: return "break"; case Token.CONTINUE: return "continue"; case Token.VAR: return "var"; case Token.WITH: return "with"; case Token.CATCH: return "catch"; case Token.FINALLY: return "finally"; case Token.RESERVED: return "reserved"; case Token.NOT: return "not"; case Token.VOID: return "void"; case Token.BLOCK: return "block"; case Token.ARRAYLIT: return "arraylit"; case Token.OBJECTLIT: return "objectlit"; case Token.LABEL: return "label"; case Token.TARGET: return "target"; case Token.LOOP: return "loop"; case Token.EXPR_VOID: return "expr_void"; case Token.EXPR_RESULT: return "expr_result"; case Token.JSR: return "jsr"; case Token.SCRIPT: return "script"; case Token.EMPTY: return "empty"; case Token.GET

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS>_REF: return "get_ref"; case Token.REF_SPECIAL: return "ref_special"; } return "<unknown="+token+">"; } /** Returns true if this node is equivalent semantically to another */ public boolean isEquivalentTo(Node node) { return isEquivalentTo(node, false, true); } /** * Returns true if this node is equivalent semantically to another and * the types are equivalent. */ public boolean isEquivalentToTyped(Node node) { return isEquivalentTo(node, true, true); } /** * @param compareJsType Whether to compare the JSTypes of the nodes. * @param recurse Whether to compare the children of the current node, if * not only the the count of the children are compared. * @return Whether this node is equivalent semantically to the provided node. */ boolean isEquivalentTo(Node node, boolean compareJsType, boolean recurse) { if (type != node.getType() || getChildCount() != node.getChildCount() || getNodeClass(this) != getNodeClass(node)) { return false; } if (compareJsType && !JSType.isEquivalent(jsType, node.getJSType())) { return false; } if (type == Token.ARRAYLIT) { try { int[] indices1 = (int[]) getProp(Node.SKIP_INDEXES_PROP); int[] indices2 = (int[]) node.getProp(Node.SKIP_INDEXES_PROP); if (indices1 == null) { if (indices2 != null) { return false; } } else if (indices2 == null) { return false; } else if (indices1.length != indices2.length) { return false; } else { for (int i = 0; i < indices1.length; i++) { if (indices1[i] != indices2[i]) { return false; } } } } catch (Exception e) { return false; } } else if (type == Token.INC || type == Token.DEC) { int post1 = this.getIntProp(INCRDECR_PROP); int post2 = node.getIntProp(INCRDECR

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS>_PROP); if (post1 != post2) { return false; } } else if (type == Token.STRING) { int quoted1 = this.getIntProp(QUOTED_PROP); int quoted2 = node.getIntProp(QUOTED_PROP); if (quoted1 != quoted2) { return false; } } if (recurse) { Node n, n2; for (n = first, n2 = node.first; n != null; n = n.next, n2 = n2.next) { if (!n.isEquivalentTo(n2, compareJsType, true)) { return false; } } } return true; } public boolean hasSideEffects() { switch (type) { case Token.EXPR_VOID: case Token.COMMA: if (last != null) return last.hasSideEffects(); else return true; case Token.HOOK: if (first == null || first.next == null || first.next.next == null) { Kit.codeBug(); } return first.next.hasSideEffects() && first.next.next.hasSideEffects(); case Token.ERROR: // Avoid cascaded error messages case Token.EXPR_RESULT: case Token.ASSIGN: case Token.ASSIGN_ADD: case Token.ASSIGN_SUB: case Token.ASSIGN_MUL: case Token.ASSIGN_DIV: case Token.ASSIGN_MOD: case Token.ASSIGN_BITOR: case Token.ASSIGN_BITXOR: case Token.ASSIGN_BITAND: case Token.ASSIGN_LSH: case Token.ASSIGN_RSH: case Token.ASSIGN_URSH: case Token.ENTERWITH: case Token.LEAVEWITH: case Token.RETURN: case Token.GOTO: case Token.IFEQ: case Token.IFNE: case Token.NEW: case Token.DELPROP: case Token.SETNAME: case Token.SETPROP: case Token.SETELEM: case Token.CALL: case Token.THROW: case Token.RETHROW: case Token.SETVAR: case Token.CATCH_SCOPE: case Token.RETURN_RESULT: case Token.SET_

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS>REF: case Token.DEL_REF: case Token.REF_CALL: case Token.TRY: case Token.SEMI: case Token.INC: case Token.DEC: case Token.EXPORT: case Token.IMPORT: case Token.IF: case Token.ELSE: case Token.SWITCH: case Token.WHILE: case Token.DO: case Token.FOR: case Token.BREAK: case Token.CONTINUE: case Token.VAR: case Token.CONST: case Token.WITH: case Token.CATCH: case Token.FINALLY: case Token.BLOCK: case Token.LABEL: case Token.TARGET: case Token.LOOP: case Token.JSR: case Token.SETPROP_OP: case Token.SETELEM_OP: case Token.LOCAL_BLOCK: case Token.SET_REF_OP: return true; default: return false; } } /** * This function takes a set of GETPROP nodes and produces a string that is * each property separated by dots. If the node ultimately under the left * sub-tree is not a simple name, this is not a valid qualified name. * * @return a null if this is not a qualified name, or a dot-separated string * of the name and properties. */ public String getQualifiedName() { if (type == Token.NAME) { return getString(); } else if (type == Token.GETPROP) { String left = getFirstChild().getQualifiedName(); if (left == null) { return null; } return left + "." + getLastChild().getString(); } else if (type == Token.THIS) { return "this"; } else { return null; } } /** * Returns whether a node corresponds to a simple or a qualified name, such as * <code>x</code> or <code>a.b.c</code> or <code>this.a</code>. */ public boolean isQualifiedName() { switch (getType()) { case Token.NAME: case Token.THIS: return true; case Token.GETPROP: return getFirstChild().isQualifiedName(); default: return false; } } /**

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS>.com (John Lenz) */ public static class SideEffectFlags { private int value = Node.SIDE_EFFECTS_ALL; public SideEffectFlags() { } public SideEffectFlags(int value) { this.value = value; } public int valueOf() { return value; } /** All side-effect occur and the returned results are non-local. */ public void setAllFlags() { value = Node.SIDE_EFFECTS_ALL; } /** No side-effects occur and the returned results are local. */ public void clearAllFlags() { value = Node.NO_SIDE_EFFECTS | Node.FLAG_LOCAL_RESULTS; } public boolean areAllFlagsSet() { return value == Node.SIDE_EFFECTS_ALL; } /** * Preserve the return result flag, but clear the others: * no global state change, no throws, no this change, no arguments change */ public void clearSideEffectFlags() { value |= Node.NO_SIDE_EFFECTS; } public void setMutatesGlobalState() { // Modify global means everything must be assumed to be modified. removeFlag(Node.FLAG_GLOBAL_STATE_UNMODIFIED); removeFlag(Node.FLAG_ARGUMENTS_UNMODIFIED); removeFlag(Node.FLAG_THIS_UNMODIFIED); } public void setThrows() { removeFlag(Node.FLAG_NO_THROWS); } public void setMutatesThis() { removeFlag(Node.FLAG_THIS_UNMODIFIED); } public void setMutatesArguments() { removeFlag(Node.FLAG_ARGUMENTS_UNMODIFIED); } public void setReturnsTainted() { removeFlag(Node.FLAG_LOCAL_RESULTS); } private void removeFlag(int flag) { value &= ~flag; } } /** * @return Whether the only side-effect is "modifies this" */ public boolean isOnlyModifiesThisCall() { return areBitFlagsSet( getSideEffectFlags() & Node.NO_SIDE_EFFECTS, Node.FLAG_GLOBAL_STATE_UNMODIFIED | Node.FLAG_ARGUMENTS_UNMODIFIED | Node.FLAG_NO_TH

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS>ROWS); } /** * Returns true if this node is a function or constructor call that * has no side effects. */ public boolean isNoSideEffectsCall() { return areBitFlagsSet(getSideEffectFlags(), NO_SIDE_EFFECTS); } /** * Returns true if this node is a function or constructor call that * returns a primitive or a local object (an object that has no other * references). */ public boolean isLocalResultCall() { return areBitFlagsSet(getSideEffectFlags(), FLAG_LOCAL_RESULTS); } /** * returns true if all the flags are set in value. */ private boolean areBitFlagsSet(int value, int flags) { return (value & flags) == flags; } /** * This should only be called for STRING nodes children of OBJECTLIT. */ public boolean isQuotedString() { return false; } /** * This should only be called for STRING nodes children of OBJECTLIT. */ public void setQuotedString() { Kit.codeBug(); } static class NodeMismatch { final Node nodeA; final Node nodeB; NodeMismatch(Node nodeA, Node nodeB) { this.nodeA = nodeA; this.nodeB = nodeB; } @Override public boolean equals(Object object) { if (object instanceof NodeMismatch) { NodeMismatch that = (NodeMismatch) object; return that.nodeA.equals(this.nodeA) && that.nodeB.equals(this.nodeB); } return false; } @Override public int hashCode() { return Objects.hashCode(nodeA, nodeB); } } }

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS>() { return false; } @Override public TernaryValue testForEquality(JSType that) { TernaryValue result = super.testForEquality(that); if (result != null) { return result; } if (that.isUnknownType() || that.isSubtype( getNativeType(JSTypeNative.OBJECT_NUMBER_STRING_BOOLEAN))) { return UNKNOWN; } return FALSE; } @Override public boolean isNumberValueType() { return true; } @Override public boolean matchesNumberContext() { return true; } @Override public boolean matchesStringContext() { return true; } @Override public boolean matchesObjectContext() { // TODO(user): Revisit this for ES4, which is stricter. return true; } @Override public String toString() { return getDisplayName(); } @Override public String getDisplayName() { return "number"; } @Override public BooleanLiteralSet getPossibleToBooleanOutcomes() { return BooleanLiteralSet.BOTH; } @Override public <T> T visit(Visitor<T> visitor) { return visitor.caseNumberType(); } @Override public JSType autoboxesTo() { return getNativeType(JSTypeNative.NUMBER_OBJECT_TYPE); } }

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS> } InstanceObjectType(JSTypeRegistry registry, FunctionType constructor, boolean isNativeType) { super(registry, null, null, isNativeType); Preconditions.checkNotNull(constructor); this.constructor = constructor; } @Override public String getReferenceName() { return getConstructor().getReferenceName(); } @Override public boolean hasReferenceName() { return getConstructor().hasReferenceName(); } @Override public ObjectType getImplicitPrototype() { return getConstructor().getPrototype(); } @Override public FunctionType getConstructor() { return constructor; } @Override boolean defineProperty(String name, JSType type, boolean inferred, boolean inExterns, Node propertyNode) { ObjectType proto = getImplicitPrototype(); if (proto != null && proto.hasOwnDeclaredProperty(name)) { return false; } return super.defineProperty(name, type, inferred, inExterns, propertyNode); } @Override public String toString() { if (constructor.hasReferenceName()) { return constructor.getReferenceName(); } else { return super.toString(); } } @Override boolean isTheObjectType() { return getConstructor().isNative() && "Object".equals(getReferenceName()); } @Override public boolean isInstanceType() { return true; } @Override public boolean isArrayType() { return getConstructor().isNative() && "Array".equals(getReferenceName()); } @Override public boolean isStringObjectType() { return getConstructor().isNative() && "String".equals(getReferenceName()); } @Override public boolean isBooleanObjectType() { return getConstructor().isNative() && "Boolean".equals(getReferenceName()); } @Override public boolean isNumberObjectType() { return getConstructor().isNative() && "Number".equals(getReferenceName()); } @Override public boolean isDateType() { return getConstructor().isNative() && "Date".equals(getReferenceName()); } @Override public boolean isRegexpType() { return getConstructor().isNative() && "RegExp".equals(getReferenceName()); } @Override public boolean isNominalType() { return hasReferenceName(); } @Override public boolean isEquivalentTo(JSType that)

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS>(JSTypeRegistry registry) { super(registry); } @Override public boolean isNullType() { return true; } @Override public boolean isNullable() { return true; } @Override public boolean matchesNumberContext() { return true; } @Override public boolean matchesObjectContext() { return false; } @Override public boolean matchesStringContext() { return true; } @Override public JSType restrictByNotNullOrUndefined() { return registry.getNativeType(JSTypeNative.NO_TYPE); } @Override public TernaryValue testForEquality(JSType that) { TernaryValue result = super.testForEquality(that); if (result != null) { return result; } if (that.isNullType() || that.isVoidType()) { return TRUE; } if (that.isUnknownType() || that.isNullable()) { return UNKNOWN; } return FALSE; } @Override public String toString() { return getDisplayName(); } @Override public String getDisplayName() { return "null"; } @Override public BooleanLiteralSet getPossibleToBooleanOutcomes() { return BooleanLiteralSet.FALSE; } @Override public <T> T visit(Visitor<T> visitor) { return visitor.caseNullType(); } }

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS>REFERENCE_ERROR_TYPE)); register(getNativeType(JSTypeNative.SYNTAX_ERROR_TYPE)); register(getNativeType(JSTypeNative.REGEXP_TYPE)); register(getNativeType(JSTypeNative.STRING_OBJECT_TYPE)); register(getNativeType(JSTypeNative.STRING_TYPE)); register(getNativeType(JSTypeNative.VOID_TYPE)); register(getNativeType(JSTypeNative.VOID_TYPE), "Undefined"); register(getNativeType(JSTypeNative.VOID_TYPE), "void"); register(getNativeType(JSTypeNative.FUNCTION_INSTANCE_TYPE), "Function"); } private void register(JSType type) { register(type, type.toString()); } private void register(JSType type, String name) { namesToTypes.put(name, type); // Add all the namespaces in which this name lives. while (name.indexOf('.') > 0) { name = name.substring(0, name.lastIndexOf('.')); namespaces.add(name); } } private void registerNativeType(JSTypeNative typeId, JSType type) { nativeTypes[typeId.ordinal()] = type; } /** * Tells the type system that {@code owner} may have a property named * {@code propertyName}. This allows the registry to keep track of what * types a property is defined upon. * * This is NOT the same as saying that {@code owner} must have a property * named type. ObjectType#hasProperty attempts to minimize false positives * ("if we're not sure, then don't type check this property"). The type * registry, on the other hand, should attempt to minimize false negatives * ("if this property is assigned anywhere in the program, it must * show up in the type registry"). */ public void registerPropertyOnType(String propertyName, JSType type) { UnionTypeBuilder typeSet = typesIndexedByProperty.get(propertyName); if (typeSet == null) { typeSet = new UnionTypeBuilder(this); typesIndexedByProperty.put(propertyName, typeSet); } typeSet.addAlternate(type); addReferenceTypeIndexedByProperty(propertyName, type); // Clear cached values that depend on typesIndexedByProperty. greatest

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS>SubtypeByProperty.remove(propertyName); } private void addReferenceTypeIndexedByProperty( String propertyName, JSType type) { if (type instanceof ObjectType && ((ObjectType) type).hasReferenceName()) { Map<String, ObjectType> typeSet = eachRefTypeIndexedByProperty.get(propertyName); if (typeSet == null) { typeSet = Maps.newHashMap(); eachRefTypeIndexedByProperty.put(propertyName, typeSet); } ObjectType objType = (ObjectType) type; typeSet.put(objType.getReferenceName(), objType); } else if (type instanceof NamedType) { addReferenceTypeIndexedByProperty( propertyName, ((NamedType) type).getReferencedType()); } else if (type instanceof UnionType) { for (JSType alternate : ((UnionType) type).getAlternates()) { addReferenceTypeIndexedByProperty(propertyName, alternate); } } } /** * Gets the greatest subtype of the {@code type} that has a property * {@code propertyName} defined on it. */ public JSType getGreatestSubtypeWithProperty( JSType type, String propertyName) { if (greatestSubtypeByProperty.containsKey(propertyName)) { return greatestSubtypeByProperty.get(propertyName) .getGreatestSubtype(type); } if (typesIndexedByProperty.containsKey(propertyName)) { JSType built = typesIndexedByProperty.get(propertyName).build(); greatestSubtypeByProperty.put(propertyName, built); return built.getGreatestSubtype(type); } return getNativeType(NO_TYPE); } /** * Returns whether the given property can possibly be set on the given type. */ public boolean canPropertyBeDefined(JSType type, String propertyName) { if (typesIndexedByProperty.containsKey(propertyName)) { for (JSType alt : typesIndexedByProperty.get(propertyName).getAlternates()) { if (!alt.getGreatestSubtype(type).isEmptyType()) { return true; } } } return false; } /** * Returns each type that has a property {@code propertyName} defined on it. * * Like most types in our type system, the collection of types returned * will be collapsed. This means that if a type is defined on

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS> * {@code Object} and on {@code Array}, it would be reasonable for this * method to return either {@code [Object, Array]} or just {@code [Object]}. */ public Iterable<JSType> getTypesWithProperty(String propertyName) { if (typesIndexedByProperty.containsKey(propertyName)) { return typesIndexedByProperty.get(propertyName).getAlternates(); } else { return ImmutableList.of(); } } /** * Returns each reference type that has a property {@code propertyName} * defined on it. * * Unlike most types in our type system, the collection of types returned * will not be collapsed. This means that if a type is defined on * {@code Object} and on {@code Array}, this method must return * {@code [Object, Array]}. It would not be correct to collapse them to * {@code [Object]}. */ public Iterable<ObjectType> getEachReferenceTypeWithProperty( String propertyName) { if (eachRefTypeIndexedByProperty.containsKey(propertyName)) { return eachRefTypeIndexedByProperty.get(propertyName).values(); } else { return ImmutableList.of(); } } /** * Increments the current generation. Clients must call this in order to * move to the next generation of type resolution, allowing types to attempt * resolution again. */ public void incrementGeneration() { for (NamedType type : resolvedNamedTypes.values()) { type.clearResolved(); } unresolvedNamedTypes.putAll(resolvedNamedTypes); resolvedNamedTypes.clear(); } boolean isLastGeneration() { return lastGeneration; } /** * Sets whether this is the last generation. In the last generation, * {@link NamedType} warns about unresolved types. */ public void setLastGeneration(boolean lastGeneration) { this.lastGeneration = lastGeneration; } /** * Tells the type system that {@code type} implements interface {@code * InterfaceInstance}. * {@code inter} must be an ObjectType for the instance of the interface as it * could be a named type and not yet have the constructor. */ void registerTypeImplementingInterface( FunctionType type, ObjectType interfaceInstance) { interfaceToImplementors.put(interfaceInstance.getReferenceName(), type);

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS>Type getNativeType(JSTypeNative typeId) { return nativeTypes[typeId.ordinal()]; } public ObjectType getNativeObjectType(JSTypeNative typeId) { return (ObjectType) getNativeType(typeId); } public FunctionType getNativeFunctionType(JSTypeNative typeId) { return (FunctionType) getNativeType(typeId); } /** * Looks up a type by name. To allow for forward references to types, an * unrecognized string has to be bound to a NamedType object that will be * resolved later. * * @param scope A scope for doing type name resolution. * @param jsTypeName The name string. * @param sourceName The name of the source file where this reference appears. * @param lineno The line number of the reference. * @return a NamedType if the string argument is not one of the known types, * otherwise the corresponding JSType object. */ public JSType getType(StaticScope<JSType> scope, String jsTypeName, String sourceName, int lineno, int charno) { JSType type = getType(jsTypeName); if (type == null) { // TODO(user): Each instance should support named type creation using // interning. NamedType namedType = new NamedType(this, jsTypeName, sourceName, lineno, charno); unresolvedNamedTypes.put(scope, namedType); type = namedType; } return type; } /** * Flushes out the current resolved and unresovled Named Types from * the type registry. This is intended to be used ONLY before a * compile is run. */ public void clearNamedTypes() { resolvedNamedTypes.clear(); unresolvedNamedTypes.clear(); } /** * Resolve all the unresolved types in the given scope. */ public void resolveTypesInScope(StaticScope<JSType> scope) { for (NamedType type : unresolvedNamedTypes.get(scope)) { type.resolve(reporter, scope); } resolvedNamedTypes.putAll(scope, unresolvedNamedTypes.removeAll(scope)); if (scope != null && scope.getParentScope() == null) { // By default, the global "this" type is just an anonymous object. // If the user

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS> has defined a Window type, make the Window the // implicit prototype of "this". PrototypeObjectType globalThis = (PrototypeObjectType) getNativeType( JSTypeNative.GLOBAL_THIS); JSType windowType = getType("Window"); if (globalThis.isUnknownType()) { ObjectType windowObjType = ObjectType.cast(windowType); if (windowObjType != null) { globalThis.setImplicitPrototype(windowObjType); } else { globalThis.setImplicitPrototype( getNativeObjectType(JSTypeNative.OBJECT_TYPE)); } } } } /** * Creates a type representing optional values of the given type. * @return the union of the type and the void type */ public JSType createOptionalType(JSType type) { if (type instanceof UnknownType || type.isAllType()) { return type; } else { return createUnionType(type, getNativeType(JSTypeNative.VOID_TYPE)); } } /** * Creates a type representing nullable values of the given type. * @return the union of the type and the Null type */ public JSType createDefaultObjectUnion(JSType type) { return shouldTolerateUndefinedValues() ? createOptionalNullableType(type) : createNullableType(type); } /** * Creates a type representing nullable values of the given type. * @return the union of the type and the Null type */ public JSType createNullableType(JSType type) { return createUnionType(type, getNativeType(JSTypeNative.NULL_TYPE)); } /** * Creates a nullabel and undefine-able value of the given type. * @return The union of the type and null and undefined. */ public JSType createOptionalNullableType(JSType type) { return createUnionType(type, getNativeType(JSTypeNative.VOID_TYPE), getNativeType(JSTypeNative.NULL_TYPE)); } /** * Creates a union type whose variants are the arguments. */ public JSType createUnionType(JSType... variants) { UnionTypeBuilder builder = new UnionTypeBuilder(this); for (JSType type : variants) { builder.addAlternate(type); } return builder.build(); } /**

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS> type or {@code null} to indicate * that the return type is unknown. */ public FunctionType createFunctionType( JSType returnType, Node parameters) { return new FunctionBuilder(this) .withParamsNode(parameters) .withReturnType(returnType) .build(); } /** * Creates a function type which can act as a constructor. * @param returnType the function's return type * @param lastVarArgs whether the last parameter type should be considered as * an extensible var_args parameter * @param parameterTypes the parameters' types */ public FunctionType createConstructorType(JSType returnType, boolean lastVarArgs, JSType... parameterTypes) { if (lastVarArgs) { return createConstructorTypeWithVarArgs(returnType, parameterTypes); } else { return createConstructorType(returnType, parameterTypes); } } /** * Create an object type. */ public ObjectType createObjectType(ObjectType implicitPrototype) { return createObjectType(null, null, implicitPrototype); } /** * Creates a record type. */ public RecordType createRecordType(Map<String, RecordProperty> properties) { return new RecordType(this, properties); } /** * Create an object type. */ public ObjectType createObjectType(String name, Node n, ObjectType implicitPrototype) { return new PrototypeObjectType(this, name, implicitPrototype); } /** * Create an anonymous object type. */ public ObjectType createAnonymousObjectType() { PrototypeObjectType type = new PrototypeObjectType(this, null, null); type.setPrettyPrint(true); return type; } /** * Creates a constructor function type. * @param name the function's name or {@code null} to indicate that the * function is anonymous. * @param source the node defining this function. Its type * ({@link Node#getType()}) must be {@link Token#FUNCTION}. * @param parameters the function's parameters or {@code null} * to indicate that the parameter types are unknown. * @param returnType the function's return type or {@code null} to indicate * that the return type is unknown. */ public FunctionType createConstructorType(String name, Node source, Node parameters, JSType returnType) {

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS>Name, scope)); } } else { JSType type = createFromTypeNodesInternal( arg, sourceName, scope); if (arg.getType() == Token.EQUALS) { boolean addSuccess = paramBuilder.addOptionalParams(type); if (!addSuccess) { reporter.warning( ScriptRuntime.getMessage0("msg.jsdoc.function.varargs"), sourceName, arg.getLineno(), "", arg.getCharno()); } } else { paramBuilder.addRequiredParams(type); } } } current = current.getNext(); } JSType returnType = createFromTypeNodesInternal(current, sourceName, scope); return new FunctionBuilder(this) .withParams(paramBuilder) .withReturnType(returnType) .withTypeOfThis(thisType) .setIsConstructor(isConstructor) .build(); } throw new IllegalStateException( "Unexpected node in type expression: " + n.toString()); } /** * Creates a RecordType from the nodes representing said record type. * @param n The node with type info. * @param sourceName The source file name. * @param scope A scope for doing type name lookups. */ private JSType createRecordTypeFromNodes(Node n, String sourceName, StaticScope<JSType> scope) { RecordTypeBuilder builder = new RecordTypeBuilder(this); // For each of the fields in the record type. for (Node fieldTypeNode = n.getFirstChild(); fieldTypeNode != null; fieldTypeNode = fieldTypeNode.getNext()) { // Get the property's name. Node fieldNameNode = fieldTypeNode; boolean hasType = false; if (fieldTypeNode.getType() == Token.COLON) { fieldNameNode = fieldTypeNode.getFirstChild(); hasType = true; } String fieldName = fieldNameNode.getString(); // TODO(user): Move this into the lexer/parser. // Remove the string literal characters around a field name, // if any. if (fieldName.startsWith("'") || fieldName.startsWith("\"")) { fieldName = fieldName.substring(1, fieldName.length() - 1); } // Get the property's type. JSType fieldType = null; if (hasType) { // We have a declared

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS> this to an ObjectType, or returns null if this is not an ObjectType. * * Does not change the underlying JS type. If you want to simulate JS * autoboxing or dereferencing, you should use autoboxesTo() or dereference(). * Those methods may change the underlying JS type. */ public ObjectType toObjectType() { return this instanceof ObjectType ? (ObjectType) this : null; } /** * Dereference a type for property access. * * Autoboxes the type, filters null/undefined, and returns the result * iff it's an object. */ public final ObjectType dereference() { JSType restricted = restrictByNotNullOrUndefined(); JSType autobox = restricted.autoboxesTo(); return ObjectType.cast(autobox == null ? restricted : autobox); } /** * Tests whether {@code this} and {@code that} are meaningfully * comparable. By meaningfully, we mean compatible types that do not lead * to step 22 of the definition of the Abstract Equality Comparison * Algorithm (11.9.3, page 55&ndash;56) of the ECMA-262 specification.<p> */ public final boolean canTestForEqualityWith(JSType that) { return this.testForEquality(that).equals(UNKNOWN); } /** * Compares {@code this} and {@code that}. * @return <ul> * <li>{@link TernaryValue#TRUE} if the comparison of values of * {@code this} type and {@code that} always succeed (such as * {@code undefined} compared to {@code null})</li> * <li>{@link TernaryValue#FALSE} if the comparison of values of * {@code this} type and {@code that} always fails (such as * {@code undefined} compared to {@code number})</li> * <li>{@link TernaryValue#UNKNOWN} if the comparison can succeed or * fail depending on the concrete values</li> * </ul> */ public TernaryValue testForEquality(JSType that) { return testForEqualityHelper(this, that); } TernaryValue testForEqualityHelper(JSType aType, JSType bType) { if (bType.is

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS>AllType() || bType.isUnknownType() || bType.isNoResolvedType() || aType.isAllType() || aType.isUnknownType() || aType.isNoResolvedType()) { return UNKNOWN; } boolean aIsEmpty = aType.isEmptyType(); boolean bIsEmpty = bType.isEmptyType(); if (aIsEmpty || bIsEmpty) { if (aIsEmpty && bIsEmpty) { return TernaryValue.TRUE; } else { return UNKNOWN; } } if (aType.isFunctionType() || bType.isFunctionType()) { JSType otherType = aType.isFunctionType() ? bType : aType; // In theory, functions are comparable to anything except // null/undefined. For example, on FF3: // function() {} == 'function () {\n}' // In practice, how a function serializes to a string is // implementation-dependent, so it does not really make sense to test // for equality with a string. JSType meet = otherType.getGreatestSubtype( getNativeType(JSTypeNative.OBJECT_TYPE)); if (meet.isNoType() || meet.isNoObjectType()) { return TernaryValue.FALSE; } else { return TernaryValue.UNKNOWN; } } if (bType.isEnumElementType() || bType.isUnionType()) { return bType.testForEquality(aType); } return null; } /** * Tests whether {@code this} and {@code that} are meaningfully * comparable using shallow comparison. By meaningfully, we mean compatible * types that are not rejected by step 1 of the definition of the Strict * Equality Comparison Algorithm (11.9.6, page 56&ndash;57) of the * ECMA-262 specification.<p> */ public final boolean canTestForShallowEqualityWith(JSType that) { return this.isSubtype(that) || that.isSubtype(this); } /** * Tests whether this type is nullable. */ public boolean isNullable() { return this.isSubtype(getNativeType(JSTypeNative.NULL_TYPE)); } /** * Gets the least supertype of {@code this

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS> used as a helper for common * getGreatestSubtype implementations. */ static JSType getGreatestSubtype(JSType thisType, JSType thatType) { if (thisType.isEquivalentTo(thatType)) { return thisType; } else if (thisType.isUnknownType() || thatType.isUnknownType()) { // The greatest subtype with any unknown type is the universal // unknown type, unless the two types are equal. return thisType.isEquivalentTo(thatType) ? thisType : thisType.getNativeType(JSTypeNative.UNKNOWN_TYPE); } else if (thisType.isSubtype(thatType)) { return filterNoResolvedType(thisType); } else if (thatType.isSubtype(thisType)) { return filterNoResolvedType(thatType); } else if (thisType.isUnionType()) { return ((UnionType) thisType).meet(thatType); } else if (thatType.isUnionType()) { return ((UnionType) thatType).meet(thisType); } else if (thisType.isObject() && thatType.isObject()) { return thisType.getNativeType(JSTypeNative.NO_OBJECT_TYPE); } return thisType.getNativeType(JSTypeNative.NO_TYPE); } /** * When computing infimums, we may get a situation like * inf(Type1, Type2) * where both types are unresolved, so they're technically * subtypes of one another. * * If this happens, filter them down to NoResolvedType. */ static JSType filterNoResolvedType(JSType type) { if (type.isNoResolvedType()) { // inf(UnresolvedType1, UnresolvedType2) needs to resolve // to the base unresolved type, so that the relation is symmetric. return type.getNativeType(JSTypeNative.NO_RESOLVED_TYPE); } else if (type instanceof UnionType) { UnionType unionType = (UnionType) type; boolean needsFiltering = false; for (JSType alt : unionType.getAlternates()) { if (alt.isNoResolvedType()) { needsFiltering = true; break; } } if (needsFiltering) { Union

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS>TypeBuilder builder = new UnionTypeBuilder(type.registry); for (JSType alt : unionType.getAlternates()) { if (!alt.isNoResolvedType()) { builder.addAlternate(alt); } } return builder.build(); } } return type; } /** * Computes the restricted type of this type knowing that the * {@code ToBoolean} predicate has a specific value. For more information * about the {@code ToBoolean} predicate, see * {@link #getPossibleToBooleanOutcomes}. * * @param outcome the value of the {@code ToBoolean} predicate * * @return the restricted type, or the Any Type if the underlying type could * not have yielded this ToBoolean value * * TODO(user): Move this method to the SemanticRAI and use the visit * method of types to get the restricted type. */ public JSType getRestrictedTypeGivenToBooleanOutcome(boolean outcome) { BooleanLiteralSet literals = getPossibleToBooleanOutcomes(); if (literals.contains(outcome)) { return this; } else { return getNativeType(JSTypeNative.NO_TYPE); } } /** * Computes the set of possible outcomes of the {@code ToBoolean} predicate * for this type. The {@code ToBoolean} predicate is defined by the ECMA-262 * standard, 3<sup>rd</sup> edition. Its behavior for simple types can be * summarized by the following table: * <table> * <tr><th>type</th><th>result</th></tr> * <tr><td>{@code undefined}</td><td>{false}</td></tr> * <tr><td>{@code null}</td><td>{false}</td></tr> * <tr><td>{@code boolean}</td><td>{true, false}</td></tr> * <tr><td>{@code number}</td><td>{true, false}</td></tr> * <tr><td>{@code string}</td><td>{true, false}</td></tr> * <tr><td>{@code Object}</td><td>{true}</td></tr> * </table> * @return the set of boolean literals for this type */ public abstract BooleanLiteralSet get

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS> by * {@link #isEquivalentTo}. It may or may not be the same object. This method * may modify the internal state of {@code this}, as long as it does * so in a way that preserves Object equality. * * For efficiency, we should only resolve a type once per compilation job. * For incremental compilations, one compilation job may need the * artifacts from a previous generation, so we will eventually need * a generational flag instead of a boolean one. */ public final JSType resolve(ErrorReporter t, StaticScope<JSType> scope) { if (resolved) { // TODO(nicksantos): Check to see if resolve() looped back on itself. // Preconditions.checkNotNull(resolveResult); if (resolveResult == null) { return registry.getNativeType(JSTypeNative.UNKNOWN_TYPE); } return resolveResult; } resolved = true; resolveResult = resolveInternal(t, scope); resolveResult.setResolvedTypeInternal(resolveResult); return resolveResult; } /** * @see #resolve */ abstract JSType resolveInternal(ErrorReporter t, StaticScope<JSType> scope); void setResolvedTypeInternal(JSType type) { resolveResult = type; resolved = true; } /** Whether the type has been resolved. */ public final boolean isResolved() { return resolved; } /** Clears the resolved field. */ public final void clearResolved() { resolved = false; resolveResult = null; } /** * A null-safe resolve. * @see #resolve */ static final JSType safeResolve( JSType type, ErrorReporter t, StaticScope<JSType> scope) { return type == null ? null : type.resolve(t, scope); } /** * Certain types have constraints on them at resolution-time. * For example, a type in an {@code @extends} annotation must be an * object. Clients should inject a validator that emits a warning * if the type does not validate, and return false. */ public boolean setValidator(Predicate<JSType> validator) { return validator.apply(this); } public static class TypePair { public final JSType typeA; public final JSType typeB;

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS> instanceof ArrowType)) { return false; } ArrowType that = (ArrowType) object; if (!returnType.isEquivalentTo(that.returnType)) { return false; } return hasEqualParameters(that); } @Override public int hashCode() { int hashCode = 0; if (returnType != null) { hashCode += returnType.hashCode(); } if (returnTypeInferred) { hashCode += 1; } if (parameters != null) { Node param = parameters.getFirstChild(); while (param != null) { JSType paramType = param.getJSType(); if (paramType != null) { hashCode += paramType.hashCode(); } param = param.getNext(); } } return hashCode; } @Override public JSType getLeastSupertype(JSType that) { throw new UnsupportedOperationException(); } @Override public JSType getGreatestSubtype(JSType that) { throw new UnsupportedOperationException(); } @Override public TernaryValue testForEquality(JSType that) { throw new UnsupportedOperationException(); } @Override public <T> T visit(Visitor<T> visitor) { throw new UnsupportedOperationException(); } @Override public BooleanLiteralSet getPossibleToBooleanOutcomes() { return BooleanLiteralSet.TRUE; } @Override JSType resolveInternal(ErrorReporter t, StaticScope<JSType> scope) { returnType = safeResolve(returnType, t, scope); if (parameters != null) { for (Node paramNode = parameters.getFirstChild(); paramNode != null; paramNode = paramNode.getNext()) { paramNode.setJSType(paramNode.getJSType().resolve(t, scope)); } } return this; } boolean hasUnknownParamsOrReturn() { if (parameters != null) { for (Node paramNode = parameters.getFirstChild(); paramNode != null; paramNode = paramNode.getNext()) { JSType type = paramNode.getJSType(); if (type == null || type.isUnknownType()) { return true; } } } return returnType == null || returnType.isUnknownType(); } }

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS> } /** * A piece of information in a marker containing a position with a string. */ public static class StringPosition extends SourcePosition<String> { } /** * A piece of information in a marker containing a position with a type. */ public static class TypePosition extends SourcePosition<Node> { public boolean hasBrackets = false; } /** * Defines a class for containing the parsing information * for this JSDocInfo. For each annotation found in the * JsDoc, a marker will be created indicating the annotation * itself, the name of the annotation (if any; for example, * a @param has a name, but a @return does not), the * textual description found on that annotation and, if applicable, * the type declaration. All this information is only collected * if documentation collection is turned on. */ public static final class Marker { public StringPosition annotation = null; public StringPosition name = null; public StringPosition description = null; public TypePosition type = null; } private LazilyInitializedInfo info = null; private LazilyInitializedDocumentation documentation = null; /** The source file containing the JSDoc. */ private String sourceName = null; private Visibility visibility = null; /** * The {@link #isConstant()}, {@link #isConstructor()}, {@link #isInterface}, * {@link #isHidden()} and {@link #shouldPreserveTry()} flags as well as * whether the {@link #type} field stores a value for {@link #getType()}, * {@link #getReturnType()} or {@link #getEnumParameterType()}. * * @see #setFlag(boolean, int) * @see #getFlag(int) * @see #setType(JSTypeExpression, int) * @see #getType(int) */ private int bitset = 0x00; /** * The type for {@link #getType()}, {@link #getReturnType()} or * {@link #getEnumParameterType()}. The knowledge of which one is recorded is * stored in the {@link #bitset} field. * * @see #setType(JSTypeExpression, int) * @see #getType(int) */ private JSTypeExpression type = null; /** * The type for {@link #

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS>4000; // @nosideeffects private static final int MASK_EXTERNS = 0x00008000; // @externs private static final int MASK_JAVADISPATCH = 0x00010000; // @javadispath private static final int MASK_NOCOMPILE = 0x00020000; // @nocompile // 3 bit type field stored in the top 3 bits of the most significant // nibble. private static final int MASK_TYPEFIELD = 0xE0000000; // 1110... private static final int TYPEFIELD_TYPE = 0x20000000; // 0010... private static final int TYPEFIELD_RETURN = 0x40000000; // 0100... private static final int TYPEFIELD_ENUM = 0x60000000; // 0110... private static final int TYPEFIELD_TYPEDEF = 0x80000000; // 1000... /** * Creates a {@link JSDocInfo} object. This object should be created using * a {@link JSDocInfoBuilder}. */ JSDocInfo(boolean includeDocumentation) { this.includeDocumentation = includeDocumentation; } // Visible for testing. public JSDocInfo() {} void setConstant(boolean value) { setFlag(value, MASK_CONSTANT); } void setConstructor(boolean value) { setFlag(value, MASK_CONSTRUCTOR); } void setDefine(boolean value) { setFlag(value, MASK_DEFINE); } void setHidden(boolean value) { setFlag(value, MASK_HIDDEN); } void setNoCheck(boolean value) { setFlag(value, MASK_NOCHECK); } void setShouldPreserveTry(boolean value) { setFlag(value, MASK_PRESERVETRY); } void setOverride(boolean value) { setFlag(value, MASK_OVERRIDE); } void setNoAlias(boolean value) { setFlag(value, MASK_NO

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS>ALIAS); } // Visible for testing. public void setDeprecated(boolean value) { setFlag(value, MASK_DEPRECATED); } void setInterface(boolean value) { setFlag(value, MASK_INTERFACE); } void setExport(boolean value) { setFlag(value, MASK_EXPORT); } void setNoShadow(boolean value) { setFlag(value, MASK_NOSHADOW); } void setImplicitCast(boolean value) { setFlag(value, MASK_IMPLICITCAST); } void setNoSideEffects(boolean value) { setFlag(value, MASK_NOSIDEEFFECTS); } void setExterns(boolean value) { setFlag(value, MASK_EXTERNS); } void setJavaDispatch(boolean value) { setFlag(value, MASK_JAVADISPATCH); } void setNoCompile(boolean value) { setFlag(value, MASK_NOCOMPILE); } private void setFlag(boolean value, int mask) { if (value) { bitset |= mask; } else { bitset &= ~mask; } } /** * Returns whether the {@code @const} annotation is present on this * {@link JSDocInfo}. */ public boolean isConstant() { return getFlag(MASK_CONSTANT) || isDefine(); } /** * Returns whether the {@code @constructor} annotation is present on this * {@link JSDocInfo}. */ public boolean isConstructor() { return getFlag(MASK_CONSTRUCTOR); } /** * Returns whether the {@code @define} annotation is present on this * {@link JSDocInfo}. If this annotation is present, then the * {@link #getType()} method will retrieve the define type. */ public boolean isDefine() { return getFlag(MASK_DEFINE); } /** * Returns whether the {@code @hidden} annotation is present on this * {@link JSDocInfo}. */ public boolean isHidden() { return getFlag(MASK_HIDDEN); } /** * Returns whether the {@code @nocheck} annotation is present on this * {@link JSDocInfo}. */ public boolean isNoTypeCheck()

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS>.authors == null) { documentation.authors = Lists.newArrayList(); } documentation.authors.add(author); return true; } /** * Documents the throws (i.e. adds it to the throws list). */ boolean documentThrows(JSTypeExpression type, String throwsDescription) { if (!lazyInitDocumentation()) { return true; } if (documentation.throwsDescriptions == null) { documentation.throwsDescriptions = new LinkedHashMap<JSTypeExpression, String>(); } if (!documentation.throwsDescriptions.containsKey(type)) { documentation.throwsDescriptions.put(type, throwsDescription); return true; } return false; } /** * Documents a parameter. Parameters are described using the {@code @param} * annotation. * * @param parameter the parameter's name * @param description the parameter's description */ boolean documentParam(String parameter, String description) { if (!lazyInitDocumentation()) { return true; } if (documentation.parameters == null) { documentation.parameters = new LinkedHashMap<String, String>(); } if (!documentation.parameters.containsKey(parameter)) { documentation.parameters.put(parameter, description); return true; } else { return false; } } /** * Documents the block-level comment/description. * * @param description the description */ boolean documentBlock(String description) { if (!lazyInitDocumentation()) { return true; } if (documentation.blockDescription != null) { return false; } documentation.blockDescription = description; return true; } /** * Documents the fileoverview comment/description. * * @param description the description */ boolean documentFileOverview(String description) { setFlag(true, MASK_FILEOVERVIEW); if (!lazyInitDocumentation()) { return true; } if (documentation.fileOverview != null) { return false; } documentation.fileOverview = description; return true; } /** * Documents the return value. Return value is described using the * {@code @return} annotation. * * @param description the return value's description */ boolean documentReturn(String description) { if (!lazyInitDocumentation()) { return true; } if

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS> } return info.parameters.get(parameter); } /** * Returns whether the parameter is defined. */ public boolean hasParameter(String parameter) { if (info == null || info.parameters == null) { return false; } return info.parameters.containsKey(parameter); } /** * Returns whether the parameter has an attached type. * * @return {@code true} if the parameter has an attached type, {@code false} * if the parameter has no attached type or does not exist. */ public boolean hasParameterType(String parameter) { return getParameterType(parameter) != null; } /** * Returns the set of names of the defined parameters. The iteration order * of the returned set is not the order in which parameters are defined. * * @return the set of names of the defined parameters. The returned set is * immutable. */ public Set<String> getParameterNames() { if (info == null || info.parameters == null) { return ImmutableSet.of(); } return ImmutableSet.copyOf(info.parameters.keySet()); } /** * Gets the number of parameters defined. */ public int getParameterCount() { if (info == null || info.parameters == null) { return 0; } return info.parameters.size(); } void setType(JSTypeExpression type) { setType(type, TYPEFIELD_TYPE); } void setReturnType(JSTypeExpression type) { setType(type, TYPEFIELD_RETURN); } void setEnumParameterType(JSTypeExpression type) { setType(type, TYPEFIELD_ENUM); } void setTypedefType(JSTypeExpression type) { setType(type, TYPEFIELD_TYPEDEF); } private void setType(JSTypeExpression type, int mask) { if ((bitset & MASK_TYPEFIELD) != 0) { throw new IllegalStateException( "API tried to add two incompatible type tags. " + "This should have been blocked and emitted a warning."); } this.bitset = (bitset & MASK_FLAGS) | mask; this.type = type; } /** * Returns the list of thrown types. */ public List<JSTypeExpression> get

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS>ThrownTypes() { if (info == null || info.thrownTypes == null) { return ImmutableList.of(); } return Collections.unmodifiableList(info.thrownTypes); } /** * Returns whether a type, specified using the {@code @type} annotation, is * present on this JSDoc. */ public boolean hasType() { return hasType(TYPEFIELD_TYPE); } /** * Returns whether an enum parameter type, specified using the {@code @enum} * annotation, is present on this JSDoc. */ public boolean hasEnumParameterType() { return hasType(TYPEFIELD_ENUM); } /** * Returns whether a typedef parameter type, specified using the * {@code @typedef} annotation, is present on this JSDoc. */ public boolean hasTypedefType() { return hasType(TYPEFIELD_TYPEDEF); } /** * Returns whether this {@link JSDocInfo} contains a type for {@code @return} * annotation. */ public boolean hasReturnType() { return hasType(TYPEFIELD_RETURN); } private boolean hasType(int mask) { return (bitset & MASK_TYPEFIELD) == mask; } /** * Gets the type specified by the {@code @type} annotation. */ public JSTypeExpression getType() { return getType(TYPEFIELD_TYPE); } /** * Gets the return type specified by the {@code @return} annotation. */ public JSTypeExpression getReturnType() { return getType(TYPEFIELD_RETURN); } /** * Gets the enum parameter type specified by the {@code @enum} annotation. */ public JSTypeExpression getEnumParameterType() { return getType(TYPEFIELD_ENUM); } /** * Gets the typedef type specified by the {@code @type} annotation. */ public JSTypeExpression getTypedefType() { return getType(TYPEFIELD_TYPEDEF); } private JSTypeExpression getType(int typefield) { if ((MASK_TYPEFIELD & bitset) == typefield) { return type; } else { return null; } } /** * Gets the type specified by the {@code @this} annotation. */ public JSTypeExpression getThisType() { return thisType;

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS> } /** * Sets the type specified by the {@code @this} annotation. */ void setThisType(JSTypeExpression type) { this.thisType = type; } /** * Returns whether this {@link JSDocInfo} contains a type for {@code @this} * annotation. */ public boolean hasThisType() { return thisType != null; } void setBaseType(JSTypeExpression type) { lazyInitInfo(); info.baseType = type; } /** * Gets the base type specified by the {@code @extends} annotation. */ public JSTypeExpression getBaseType() { return (info == null) ? null : info.baseType; } /** * Gets the description specified by the {@code @desc} annotation. */ public String getDescription() { return (info == null) ? null : info.description; } void setDescription(String desc) { lazyInitInfo(); info.description = desc; } /** * Gets the meaning specified by the {@code @meaning} annotation. * * In localization systems, two messages with the same content but * different "meanings" may be translated differently. By default, we * use the name of the variable that the message is initialized to as * the "meaning" of the message. * * But some code generators (like Closure Templates) inject their own * meaning with the jsdoc {@code @meaning} annotation. */ public String getMeaning() { return (info == null) ? null : info.meaning; } void setMeaning(String meaning) { lazyInitInfo(); info.meaning = meaning; } /** * Gets the name we're lending to in a {@code @lends} annotation. * * In many reflection APIs, you pass an anonymous object to a function, * and that function mixes the anonymous object into another object. * The {@code @lends} annotation allows the type system to track * those property assignments. */ public String getLendsName() { return (info == null) ? null : info.lendsName; } void setLendsName(String name) { lazyInitInfo(); info.lendsName = name;

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS> or null if none specified. */ public String getFileOverview() { return documentation == null ? null : documentation.fileOverview; } /** Gets the name of the source file that contains this JSDoc. */ public String getSourceName() { return sourceName; } /** Gets the list of all markers for the documentation in this JSDoc. */ public Collection<Marker> getMarkers() { return documentation == null ? null : documentation.markers; } /** Sets the name of the source file that contains this JSDoc. */ void setSourceName(String sourceName) { this.sourceName = sourceName; } /** Gets the template type name. */ public String getTemplateTypeName() { if (info == null) { return null; } return info.templateTypeName; } /** * Returns a collection of all type nodes that are a part of this JSDocInfo. * This includes @type, @this, @extends, @implements, @param, @throws, * and @return. Any future type specific JSDoc should make sure to add the * appropriate nodes here. * @return collection of all type nodes */ public Collection<Node> getTypeNodes() { List<Node> nodes = Lists.newArrayList(); if (type != null) { nodes.add(type.getRoot()); } if (thisType != null) { nodes.add(thisType.getRoot()); } if (info != null) { if (info.baseType != null) { nodes.add(info.baseType.getRoot()); } if (info.implementedInterfaces != null) { for (JSTypeExpression interfaceType : info.implementedInterfaces) { nodes.add(interfaceType.getRoot()); } } if (info.parameters != null) { for (JSTypeExpression parameterType : info.parameters.values()) { if (parameterType != null) { nodes.add(parameterType.getRoot()); } } } if (info.thrownTypes != null) { for (JSTypeExpression thrownType : info.thrownTypes) { if (thrownType != null) { nodes.add(thrownType.getRoot()); } } } } return nodes; }

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS> RecordTypeBuilder(registry); } protected JSType createNullableType(JSType type) { return registry.createNullableType(type); } protected JSType createOptionalType(JSType type) { return registry.createOptionalType(type); } /** * Asserts that a Node representing a type expression resolves to the * correct {@code JSType}. */ protected void assertTypeEquals(JSType expected, Node actual) { assertTypeEquals(expected, new JSTypeExpression(actual, "")); } /** * Asserts that a a type expression resolves to the correct {@code JSType}. */ protected void assertTypeEquals(JSType expected, JSTypeExpression actual) { assertEquals(expected, resolve(actual)); } /** * Resolves a type expression, expecting the given warnings. */ protected JSType resolve(JSTypeExpression n, String... warnings) { errorReporter.setWarnings(warnings); return n.evaluate(null, registry); } /** * A definition of all extern types. This should be kept in sync with * javascript/externs/es3.js. This is used to check that the builtin types * declared in {@link JSTypeRegistry} have the same type as that in the * externs. It can also be used for any tests that want to use builtin types * in their externs. */ public static final String ALL_NATIVE_EXTERN_TYPES = "/**\n" + " * @constructor\n" + " * @param {*} opt_value\n" + " */\n" + "function Object(opt_value) {}\n" + "\n" + "/**\n" + " * @constructor\n" + " * @extends {Object}\n" + " * @param {*} var_args\n" + " */\n" + "\n" + "function Function(var_args) {}\n" + "/**\n" + " * @constructor\n" + " * @extends {Object}\n" + " * @param {*} var_args\n" + " * @return {!Array}\n" + " */\n" + "function Array(var_args) {}\n" + "\n"

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS>_INITIALIZER = DiagnosticType.warning( "JSC_IFACE_INITIALIZER_NOT_IFACE", "Interface {0} must be initialized at declaration"); static final DiagnosticType CONSTRUCTOR_EXPECTED = DiagnosticType.warning( "JSC_REFLECT_CONSTRUCTOR_EXPECTED", "Constructor expected as first argument"); static final DiagnosticType UNKNOWN_LENDS = DiagnosticType.warning( "JSC_UNKNOWN_LENDS", "Variable {0} not declared before @lends annotation."); static final DiagnosticType LENDS_ON_NON_OBJECT = DiagnosticType.warning( "JSC_LENDS_ON_NON_OBJECT", "May only lend properties to object types. {0} has type {1}."); private final AbstractCompiler compiler; private final ErrorReporter typeParsingErrorReporter; private final TypeValidator validator; private final CodingConvention codingConvention; private final JSTypeRegistry typeRegistry; private final List<ObjectType> delegateProxyPrototypes = Lists.newArrayList(); /** * Defer attachment of types to nodes until all type names * have been resolved. Then, we can resolve the type and attach it. */ private class DeferredSetType { final Node node; final JSType type; DeferredSetType(Node node, JSType type) { Preconditions.checkNotNull(node); Preconditions.checkNotNull(type); this.node = node; this.type = type; // Other parts of this pass may read off the node. // (like when we set the LHS of an assign with a typed RHS function.) node.setJSType(type); } void resolve(Scope scope) { node.setJSType(type.resolve(typeParsingErrorReporter, scope)); } } TypedScopeCreator(AbstractCompiler compiler) { this(compiler, compiler.getCodingConvention()); } TypedScopeCreator(AbstractCompiler compiler, CodingConvention codingConvention) { this.compiler = compiler; this.validator = compiler.getTypeValidator(); this.codingConvention = codingConvention; this.typeRegistry = compiler.getTypeRegistry(); this.typeParsingErrorReporter = typeRegistry.getErrorReporter(); } /** * Creates a scope with all types declared. Declares newly discovered types * and type properties in

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS> the type registry. */ public Scope createScope(Node root, Scope parent) { // Constructing the global scope is very different than constructing // inner scopes, because only global scopes can contain named classes that // show up in the type registry. Scope newScope = null; AbstractScopeBuilder scopeBuilder = null; if (parent == null) { // Find all the classes in the global scope. newScope = createInitialScope(root); GlobalScopeBuilder globalScopeBuilder = new GlobalScopeBuilder(newScope); scopeBuilder = globalScopeBuilder; NodeTraversal.traverse(compiler, root, scopeBuilder); } else { newScope = new Scope(parent, root); LocalScopeBuilder localScopeBuilder = new LocalScopeBuilder(newScope); scopeBuilder = localScopeBuilder; localScopeBuilder.build(); } scopeBuilder.resolveStubDeclarations(); scopeBuilder.resolveTypes(); // Gather the properties in each function that we found in the // global scope, if that function has a @this type that we can // build properties on. for (Node functionNode : scopeBuilder.nonExternFunctions) { JSType type = functionNode.getJSType(); if (type != null && type instanceof FunctionType) { FunctionType fnType = (FunctionType) type; ObjectType fnThisType = fnType.getTypeOfThis(); if (!fnThisType.isUnknownType()) { NodeTraversal.traverse(compiler, functionNode.getLastChild(), scopeBuilder.new CollectProperties(fnThisType)); } } } if (parent == null) { codingConvention.defineDelegateProxyPrototypeProperties( typeRegistry, newScope, delegateProxyPrototypes); } return newScope; } /** * Create the outermost scope. This scope contains native binding such as * {@code Object}, {@code Date}, etc. */ @VisibleForTesting Scope createInitialScope(Node root) { NodeTraversal.traverse( compiler, root, new DiscoverEnumsAndTypedefs(typeRegistry)); Scope s = new Scope(root, compiler); declareNativeFunctionType(s, ARRAY_FUNCTION_TYPE); declareNativeFunctionType(s, BOOLEAN_OBJECT_FUNCTION_TYPE); declareNativeFunctionType(s, DATE_FUNCTION_TYPE); declareNativeFunctionType(s, ERROR_FUNCTION

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS> builidng. */ final Scope scope; private final List<DeferredSetType> deferredSetTypes = Lists.newArrayList(); /** * Functions that we found in the global scope and not in externs. */ private final List<Node> nonExternFunctions = Lists.newArrayList(); /** * Type-less stubs. * * If at the end of traversal, we still don't have types for these * stubs, then we should declare UNKNOWN types. */ private final List<StubDeclaration> stubDeclarations = Lists.newArrayList(); /** * The current source file that we're in. */ private String sourceName = null; private AbstractScopeBuilder(Scope scope) { this.scope = scope; } void setDeferredType(Node node, JSType type) { deferredSetTypes.add(new DeferredSetType(node, type)); } void resolveTypes() { // Resolve types and attach them to nodes. for (DeferredSetType deferred : deferredSetTypes) { deferred.resolve(scope); } // Resolve types and attach them to scope slots. Iterator<Var> vars = scope.getVars(); while (vars.hasNext()) { vars.next().resolveType(typeParsingErrorReporter); } // Tell the type registry that any remaining types // are unknown. typeRegistry.resolveTypesInScope(scope); } @Override public final boolean shouldTraverse(NodeTraversal nodeTraversal, Node n, Node parent) { if (n.getType() == Token.FUNCTION || n.getType() == Token.SCRIPT) { sourceName = (String) n.getProp(Node.SOURCENAME_PROP); } // We do want to traverse the name of a named function, but we don't // want to traverse the arguments or body. boolean descend = parent == null || parent.getType() != Token.FUNCTION || n == parent.getFirstChild() || parent == scope.getRootNode(); if (descend) { // Handle hoisted functions on pre-order traversal, so that they // get hit before other things in the scope. if (NodeUtil.isStatementParent(n)) { for (Node child = n.getFirstChild(); child != null; child = child.getNext()) {

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS> n.setJSType(getNativeType(BOOLEAN_TYPE)); break; case Token.REGEXP: n.setJSType(getNativeType(REGEXP_TYPE)); break; case Token.REF_SPECIAL: n.setJSType(getNativeType(UNKNOWN_TYPE)); break; case Token.OBJECTLIT: defineObjectLiteral(t, n); break; // NOTE(nicksantos): If we ever support Array tuples, // we will need to put ARRAYLIT here as well. } } private void defineObjectLiteral(NodeTraversal t, Node objectLit) { // Handle the @lends annotation. JSType type = null; JSDocInfo info = objectLit.getJSDocInfo(); if (info != null && info.getLendsName() != null) { String lendsName = info.getLendsName(); Var lendsVar = scope.getVar(lendsName); if (lendsVar == null) { compiler.report( JSError.make(sourceName, objectLit, UNKNOWN_LENDS, lendsName)); } else { type = lendsVar.getType(); if (type == null) { type = typeRegistry.getNativeType(UNKNOWN_TYPE); } if (!type.isSubtype(typeRegistry.getNativeType(OBJECT_TYPE))) { compiler.report( JSError.make(sourceName, objectLit, LENDS_ON_NON_OBJECT, lendsName, type.toString())); type = null; } else { objectLit.setJSType(type); } } } info = getBestJSDocInfo(objectLit); Node lValue = getBestLValue(objectLit); String lValueName = getBestLValueName(lValue); boolean createdEnumType = false; if (info != null && info.hasEnumParameterType()) { type = createEnumTypeFromNodes(objectLit, lValueName, info, lValue); createdEnumType = true; } if (type == null) { type = typeRegistry.createAnonymousObjectType(); } setDeferredType(objectLit, type); // If this is an enum, the properties were already taken care of above. if

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS> (!createdEnumType) { processObjectLitProperties( t, objectLit, ObjectType.cast(objectLit.getJSType())); } } /** * Process an object literal and all the types on it. * @param objLit The OBJECTLIT node. * @param objLitType The type of the OBJECTLIT node. This might be a named * type, because of the lends annotation. */ void processObjectLitProperties( NodeTraversal t, Node objLit, ObjectType objLitType) { for (Node keyNode = objLit.getFirstChild(); keyNode != null; keyNode = keyNode.getNext()) { Node value = keyNode.getFirstChild(); String memberName = NodeUtil.getObjectLitKeyName(keyNode); JSDocInfo info = keyNode.getJSDocInfo(); JSType valueType = getDeclaredType( t.getSourceName(), info, keyNode, value); JSType keyType = NodeUtil.getObjectLitKeyTypeFromValueType( keyNode, valueType); if (keyType != null) { // Try to declare this property in the current scope if it // has an authoritative name. String qualifiedName = getBestLValueName(keyNode); if (qualifiedName != null) { defineSlot(keyNode, objLit, qualifiedName, keyType, false); } else { setDeferredType(keyNode, keyType); } if (objLitType != null) { // Declare this property on its object literal. boolean isExtern = t.getInput() != null && t.getInput().isExtern(); objLitType.defineDeclaredProperty( memberName, keyType, isExtern, keyNode); } } } } /** * Returns the type specified in a JSDoc annotation near a GETPROP or NAME. * * Extracts type information from either the {@code @type} tag or from * the {@code @return} and {@code @param} tags. */ private JSType getDeclaredTypeInAnnotation(String sourceName, Node node, JSDocInfo info) { JSType jsType = null; Node objNode = node.getType() == Token.GETPROP ? node.getFirstChild() : NodeUtil.isObjectLitKey(node, node

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS>.getParent()) ? node.getParent() : null; if (info != null) { if (info.hasType()) { jsType = info.getType().evaluate(scope, typeRegistry); } else if (FunctionTypeBuilder.isFunctionTypeDeclaration(info)) { String fnName = node.getQualifiedName(); jsType = createFunctionTypeFromNodes( null, fnName, info, node); } } return jsType; } /** * Asserts that it's ok to define this node's name. * The node should have a source name and be of the specified type. */ void assertDefinitionNode(Node n, int type) { Preconditions.checkState(sourceName != null); Preconditions.checkState(n.getType() == type); } /** * Defines a catch parameter. */ void defineCatch(Node n, Node parent) { assertDefinitionNode(n, Token.CATCH); Node catchName = n.getFirstChild(); defineSlot(catchName, n, null); } /** * Defines a VAR initialization. */ void defineVar(Node n, Node parent) { assertDefinitionNode(n, Token.VAR); JSDocInfo info = n.getJSDocInfo(); if (n.hasMoreThanOneChild()) { if (info != null) { // multiple children compiler.report(JSError.make(sourceName, n, MULTIPLE_VAR_DEF)); } for (Node name : n.children()) { defineName(name, n, parent, name.getJSDocInfo()); } } else { Node name = n.getFirstChild(); defineName(name, n, parent, (info != null) ? info : name.getJSDocInfo()); } } /** * Defines a function literal. */ void defineFunctionLiteral(Node n, Node parent) { assertDefinitionNode(n, Token.FUNCTION); // Determine the name and JSDocInfo and lvalue for the function. // Any of these may be null. Node lValue = getBestLValue(n); JSDocInfo info = getBestJSDocInfo(n); String functionName = getBestLValueName(lValue); FunctionType functionType = createFunctionType

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS>FromNodes(n, functionName, info, lValue); // Assigning the function type to the function node setDeferredType(n, functionType); // Declare this symbol in the current scope iff it's a function // declaration. Otherwise, the declaration will happen in other // code paths. if (NodeUtil.isFunctionDeclaration(n)) { defineSlot(n.getFirstChild(), n, functionType); } } /** * Defines a variable based on the {@link Token#NAME} node passed. * @param name The {@link Token#NAME} node. * @param var The parent of the {@code name} node, which must be a * {@link Token#VAR} node. * @param parent {@code var}'s parent. * @param info the {@link JSDocInfo} information relating to this * {@code name} node. */ private void defineName(Node name, Node var, Node parent, JSDocInfo info) { Node value = name.getFirstChild(); // variable's type JSType type = getDeclaredType(sourceName, info, name, value); if (type == null) { // The variable's type will be inferred. CompilerInput input = compiler.getInput(sourceName); Preconditions.checkNotNull(input, sourceName); type = input.isExtern() ? getNativeType(UNKNOWN_TYPE) : null; } defineSlot(name, var, type); } /** * If a variable is assigned a function literal in the global scope, * make that a declared type (even if there's no doc info). * There's only one exception to this rule: * if the return type is inferred, and we're in a local * scope, we should assume the whole function is inferred. */ private boolean shouldUseFunctionLiteralType( FunctionType type, JSDocInfo info, Node lValue) { if (info != null) { return true; } if (lValue != null && NodeUtil.isObjectLitKey(lValue, lValue.getParent())) { return false; } return scope.isGlobal() || !type.isReturnTypeInferred(); } /** * Creates a new function type, based on the given nodes. * * This handles

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS>; if (info != null && info.hasType()) { JSType type = info.getType().evaluate(scope, typeRegistry); // Known to be not null since we have the FUNCTION token there. type = type.restrictByNotNullOrUndefined(); if (type.isFunctionType()) { functionType = (FunctionType) type; functionType.setJSDocInfo(info); } } if (functionType == null) { // Find the type of any overridden function. FunctionType overriddenPropType = null; if (lvalueNode != null && lvalueNode.getType() == Token.GETPROP && lvalueNode.isQualifiedName()) { Var var = scope.getVar( lvalueNode.getFirstChild().getQualifiedName()); if (var != null) { ObjectType ownerType = ObjectType.cast(var.getType()); if (ownerType != null) { String propName = lvalueNode.getLastChild().getString(); overriddenPropType = findOverriddenFunction(ownerType, propName); } } } FunctionTypeBuilder builder = new FunctionTypeBuilder(name, compiler, errorRoot, sourceName, scope) .setSourceNode(fnRoot) .inferFromOverriddenFunction(overriddenPropType, parametersNode) .inferTemplateTypeName(info) .inferReturnType(info) .inferInheritance(info); // Infer the context type. boolean searchedForThisType = false; if (lvalueNode != null && lvalueNode.getType() == Token.GETPROP) { Node objNode = lvalueNode.getFirstChild(); if (objNode.getType() == Token.GETPROP && objNode.getLastChild().getString().equals("prototype")) { builder.inferThisType(info, objNode.getFirstChild()); searchedForThisType = true; } else if (objNode.getType() == Token.THIS) { builder.inferThisType(info, objNode.getJSType()); searchedForThisType = true; } } if (!searchedForThisType) { builder.inferThisType(info, (Node) null); } functionType = builder .inferParameterTypes(parametersNode, info) .inferReturnStatementsAsLastResort(fnBlock) .buildAnd

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS>Registry.createEnumType(name, elementsType); if (rValue != null && rValue.getType() == Token.OBJECTLIT) { // collect enum elements Node key = rValue.getFirstChild(); while (key != null) { String keyName = NodeUtil.getStringValue(key); if (keyName == null) { // GET and SET don't have a String value; compiler.report( JSError.make(sourceName, key, ENUM_NOT_CONSTANT, keyName)); } else if (enumType.hasOwnProperty(keyName)) { compiler.report(JSError.make(sourceName, key, ENUM_DUP, keyName)); } else if (!codingConvention.isValidEnumKey(keyName)) { compiler.report( JSError.make(sourceName, key, ENUM_NOT_CONSTANT, keyName)); } else { enumType.defineElement(keyName, key); } key = key.getNext(); } } } if (name != null && scope.isGlobal()) { typeRegistry.declareType(name, enumType.getElementsType()); } return enumType; } /** * Defines a typed variable. The defining node will be annotated with the * variable's type or {@code null} if its type is inferred. * @param name the defining node. It must be a {@link Token#NAME}. * @param parent the {@code name}'s parent. * @param type the variable's type. It may be {@code null}, in which case * the variable's type will be inferred. */ private void defineSlot(Node name, Node parent, JSType type) { defineSlot(name, parent, type, type == null); } /** * Defines a typed variable. The defining node will be annotated with the * variable's type of {@link JSTypeNative#UNKNOWN_TYPE} if its type is * inferred. * * Slots may be any variable or any qualified name in the global scope. * * @param n the defining NAME or GETPROP node. * @param parent the {@code n}'s parent. * @param type the variable's type. It may be {@code null} if * {@code inferred} is {@code true}. */

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS> void defineSlot(Node n, Node parent, JSType type, boolean inferred) { Preconditions.checkArgument(inferred || type != null); // Only allow declarations of NAMEs and qualfied names. // Object literal keys will have to compute their names themselves. if (n.getType() == Token.NAME) { Preconditions.checkArgument( parent.getType() == Token.FUNCTION || parent.getType() == Token.VAR || parent.getType() == Token.LP || parent.getType() == Token.CATCH); } else { Preconditions.checkArgument( n.getType() == Token.GETPROP && (parent.getType() == Token.ASSIGN || parent.getType() == Token.EXPR_RESULT)); } defineSlot(n, parent, n.getQualifiedName(), type, inferred); } /** * Defines a symbol in the current scope. * * @param n the defining NAME or GETPROP or object literal key node. * @param parent the {@code n}'s parent. * @param variableName The name that this should be known by. * @param type the variable's type. It may be {@code null} if * {@code inferred} is {@code true}. * @param inferred Whether the type is inferred or declared. */ void defineSlot(Node n, Node parent, String variableName, JSType type, boolean inferred) { Preconditions.checkArgument(!variableName.isEmpty()); boolean isGlobalVar = n.getType() == Token.NAME && scope.isGlobal(); boolean shouldDeclareOnGlobalThis = isGlobalVar && (parent.getType() == Token.VAR || parent.getType() == Token.FUNCTION); // If n is a property, then we should really declare it in the // scope where the root object appears. This helps out people // who declare "global" names in an anonymous namespace. Scope scopeToDeclareIn = scope; if (n.getType() == Token.GETPROP && !scope.isGlobal() && isQnameRootedInGlobalScope(n)) { Scope globalScope = scope.getGlobalScope(); // don't try to declare in the global scope if there's // already a symbol there with this name. if (!globalScope.isDeclared(variableName, false)) { scopeToDeclareIn

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS> = scope.getGlobalScope(); } } // declared in closest scope? if (scopeToDeclareIn.isDeclared(variableName, false)) { Var oldVar = scopeToDeclareIn.getVar(variableName); validator.expectUndeclaredVariable( sourceName, n, parent, oldVar, variableName, type); } else { if (!inferred) { setDeferredType(n, type); } CompilerInput input = compiler.getInput(sourceName); boolean isExtern = input.isExtern(); Var newVar = scopeToDeclareIn.declare(variableName, n, type, input, inferred); if (shouldDeclareOnGlobalThis) { ObjectType globalThis = typeRegistry.getNativeObjectType(GLOBAL_THIS); if (inferred) { globalThis.defineInferredProperty(variableName, type == null ? getNativeType(JSTypeNative.NO_TYPE) : type, isExtern, n); } else { globalThis.defineDeclaredProperty(variableName, type, isExtern, n); } } if (type instanceof EnumType) { Node initialValue = newVar.getInitialValue(); boolean isValidValue = initialValue != null && (initialValue.getType() == Token.OBJECTLIT || initialValue.isQualifiedName()); if (!isValidValue) { compiler.report(JSError.make(sourceName, n, ENUM_INITIALIZER)); } } // We need to do some additional work for constructors and interfaces. if (type instanceof FunctionType && // We don't want to look at empty function types. !type.isEmptyType()) { FunctionType fnType = (FunctionType) type; if ((fnType.isConstructor() || fnType.isInterface()) && !fnType.equals(getNativeType(U2U_CONSTRUCTOR_TYPE))) { // Declare var.prototype in the scope chain. FunctionType superClassCtor = fnType.getSuperClassConstructor(); scopeToDeclareIn.declare(variableName + ".prototype", n, fnType.getPrototype(), input, /* declared iff there's an explicit supertype */ superClassCtor == null || superClassCtor.getInstanceType().equals( getNativeType(OBJECT_TYPE))); // Make sure the variable is initialized

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS> to something if // it constructs itself. if (newVar.getInitialValue() == null && !isExtern && // We want to make sure that when we declare a new instance // type (with @constructor) that there's actually a ctor for it. // This doesn't apply to structural constructors // (like function(new:Array). Checking the constructed // type against the variable name is a sufficient check for // this. variableName.equals( fnType.getInstanceType().getReferenceName())) { compiler.report( JSError.make(sourceName, n, fnType.isConstructor() ? CTOR_INITIALIZER : IFACE_INITIALIZER, variableName)); } } } } if (isGlobalVar && "Window".equals(variableName) && type instanceof FunctionType && type.isConstructor()) { FunctionType globalThisCtor = typeRegistry.getNativeObjectType(GLOBAL_THIS).getConstructor(); globalThisCtor.getInstanceType().clearCachedValues(); globalThisCtor.getPrototype().clearCachedValues(); globalThisCtor .setPrototypeBasedOn(((FunctionType) type).getInstanceType()); } } /** * Check if the given node is a property of a name in the global scope. */ private boolean isQnameRootedInGlobalScope(Node n) { Node root = NodeUtil.getRootOfQualifiedName(n); if (root.getType() == Token.NAME) { Var var = scope.getVar(root.getString()); if (var != null) { return var.isGlobal(); } } return false; } /** * Look for a type declaration on a property assignment * (in an ASSIGN or an object literal key). * * @param info The doc info for this property. * @param lValue The l-value node. * @param rValue The node that {@code n} is being initialized to, * or {@code null} if this is a stub declaration. */ private JSType getDeclaredType(String sourceName, JSDocInfo info, Node lValue, @Nullable Node rValue) { if (info != null && info.hasType()) { return getDeclaredTypeInAnnotation(sourceName, lValue, info); } else if (r

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS> if (relationship != null) { ObjectType superClass = ObjectType.cast( typeRegistry.getType(relationship.superclassName)); ObjectType subClass = ObjectType.cast( typeRegistry.getType(relationship.subclassName)); if (superClass != null && subClass != null) { FunctionType superCtor = superClass.getConstructor(); FunctionType subCtor = subClass.getConstructor(); if (relationship.type == SubclassType.INHERITS) { validator.expectSuperType(t, n, superClass, subClass); } if (superCtor != null && subCtor != null) { codingConvention.applySubclassRelationship( superCtor, subCtor, relationship.type); } } } String singletonGetterClassName = codingConvention.getSingletonGetterClassName(n); if (singletonGetterClassName != null) { ObjectType objectType = ObjectType.cast( typeRegistry.getType(singletonGetterClassName)); if (objectType != null) { FunctionType functionType = objectType.getConstructor(); if (functionType != null) { FunctionType getterType = typeRegistry.createFunctionType(objectType); codingConvention.applySingletonGetter(functionType, getterType, objectType); } } } DelegateRelationship delegateRelationship = codingConvention.getDelegateRelationship(n); if (delegateRelationship != null) { applyDelegateRelationship(delegateRelationship); } ObjectLiteralCast objectLiteralCast = codingConvention.getObjectLiteralCast(t, n); if (objectLiteralCast != null) { ObjectType type = ObjectType.cast( typeRegistry.getType(objectLiteralCast.typeName)); if (type != null && type.getConstructor() != null) { setDeferredType(objectLiteralCast.objectNode, type); } else { compiler.report(JSError.make(t.getSourceName(), n, CONSTRUCTOR_EXPECTED)); } } } /** * Apply special properties that only apply to delegates. */ private void applyDelegateRelationship( DelegateRelationship delegateRelationship) { ObjectType delegatorObject = ObjectType.cast( typeRegistry.getType(delegateRelationship.delegator)); ObjectType delegateBaseObject = ObjectType.cast( typeRegistry.getType(delegateRelationship.delegateBase)); ObjectType delegateSuperObject = ObjectType.cast( typeRegistry.getType(codingConvention

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS> n.getParent(); String qName = n.getQualifiedName(); String propName = n.getLastChild().getString(); String ownerName = stub.ownerName; boolean isExtern = stub.isExtern; if (scope.isDeclared(qName, false)) { continue; } // If we see a stub property, make sure to register this property // in the type registry. ObjectType ownerType = getObjectSlot(ownerName); ObjectType unknownType = typeRegistry.getNativeObjectType(UNKNOWN_TYPE); defineSlot(n, parent, unknownType, true); if (ownerType != null && (isExtern || ownerType.isFunctionPrototypeType())) { // If this is a stub for a prototype, just declare it // as an unknown type. These are seen often in externs. ownerType.defineInferredProperty( propName, unknownType, isExtern, n); } else { typeRegistry.registerPropertyOnType( propName, ownerType == null ? unknownType : ownerType); } } } /** * Collects all declared properties in a function, and * resolves them relative to the global scope. */ private final class CollectProperties extends AbstractShallowStatementCallback { private final ObjectType thisType; CollectProperties(ObjectType thisType) { this.thisType = thisType; } public void visit(NodeTraversal t, Node n, Node parent) { if (n.getType() == Token.EXPR_RESULT) { Node child = n.getFirstChild(); switch (child.getType()) { case Token.ASSIGN: maybeCollectMember(t, child.getFirstChild(), child, child.getLastChild()); break; case Token.GETPROP: maybeCollectMember(t, child, child, null); break; } } } private void maybeCollectMember(NodeTraversal t, Node member, Node nodeWithJsDocInfo, @Nullable Node value) { JSDocInfo info = nodeWithJsDocInfo.getJSDocInfo(); // Do nothing if there is no JSDoc type info, or // if the node is not a member expression, or // if the member expression is not of the form: this.someProperty. if (info == null || member.getType() !=

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS> Token.GETPROP || member.getFirstChild().getType() != Token.THIS) { return; } member.getFirstChild().setJSType(thisType); JSType jsType = getDeclaredType(t.getSourceName(), info, member, value); Node name = member.getLastChild(); if (jsType != null && (name.getType() == Token.NAME || name.getType() == Token.STRING)) { thisType.defineDeclaredProperty( name.getString(), jsType, false /* functions with implementations are not in externs */, member); } } } // end CollectProperties } /** * A stub declaration without any type information. */ private static final class StubDeclaration { private final Node node; private final boolean isExtern; private final String ownerName; private StubDeclaration(Node node, boolean isExtern, String ownerName) { this.node = node; this.isExtern = isExtern; this.ownerName = ownerName; } } /** * A shallow traversal of the global scope to build up all classes, * functions, and methods. */ private final class GlobalScopeBuilder extends AbstractScopeBuilder { private GlobalScopeBuilder(Scope scope) { super(scope); } /** * Visit a node in the global scope, and add anything it declares to the * global symbol table. * * @param t The current traversal. * @param n The node being visited. * @param parent The parent of n */ @Override public void visit(NodeTraversal t, Node n, Node parent) { super.visit(t, n, parent); switch (n.getType()) { case Token.ASSIGN: // Handle typedefs. checkForOldStyleTypedef(t, n); break; case Token.VAR: // Handle typedefs. if (n.hasOneChild()) { checkForOldStyleTypedef(t, n); checkForTypedef(t, n.getFirstChild(), n.getJSDocInfo()); } break; } } @Override void maybeDeclareQualifiedName( NodeTraversal t, JSDocInfo info, Node n, Node parent, Node rhsValue) { checkForTypedef(t, n, info

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS>/* * Copyright 2008 The Closure Compiler Authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.javascript.jscomp.CheckLevel; /** * Class that allows to flexibly manage what to do with a reported * warning/error. * * Guard has several choices: * - return OFF - suppress the warning/error * - return WARNING * - return ERROR report it with high severity * - return null. Does not know what to do with it. Lets the other guard * decide what to do with it. * * Although the interface is very simple it allows you easyly customize what * warnings you are interested in. * * For example there are could be several implementations: * StrictGuard - {return ERROR}. All warnings should be treat as errors. * SilentGuard - {if (WARNING) return OFF}. Suppress all warnings but still * fail if js has errors. * WhitelistGuard (if !whitelistErrors.contains(error) return ERROR) return * error if it does not present in the whitelist. * * @author anatol@google.com (Anatol Pomazau) */ public abstract class WarningsGuard { public static enum Priority { MAX(1), MIN(100), STRICT(100), DEFAULT(50), SUPPRESS_BY_WHITELIST(40), SUPPRESS_DOC(20), FILTER_BY_PATH(1); final int value; Priority(int value) { this.value = value; } public int getValue() { return value; } }

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS> /** * Returns a new check level for a given error. OFF - suppress it, ERROR - * report as error. null means that this guard does not know what to do * with the error. Null is extremely helpful when you have a chain of * guards. If current guard returns null, then the next in the chain should * process it. * * @param error a reported error. * @return what level given error should have. */ public abstract CheckLevel level(JSError error); /** * The priority in which warnings guards are applied. Lower means the * guard will be applied sooner. Expressed on a scale of 1 to 100. */ protected int getPriority() { return Priority.DEFAULT.value; } /** * Returns whether all warnings in the given diagnostic group will be * filtered out. Used to determine which passes to skip. * * @param group A group of DiagnosticTypes. * @return Whether all warnings of these types are disabled by this guard. */ protected boolean disables(DiagnosticGroup group) { return false; } /** * Returns whether any of the warnings in the given diagnostic group will be * upgraded to a warning or error. * * @param group A group of DiagnosticTypes. * @return Whether any warnings of these types are enabled by this guard. */ protected boolean enables(DiagnosticGroup group) { return false; } }

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS> registry, this, baseType, isNativeObjectType())); } else { prototype.setImplicitPrototype(baseType); } } /** * Sets the prototype. * @param prototype the prototype. If this value is {@code null} it will * silently be discarded. */ public boolean setPrototype(FunctionPrototypeType prototype) { if (prototype == null) { return false; } // getInstanceType fails if the function is not a constructor if (isConstructor() && prototype == getInstanceType()) { return false; } boolean replacedPrototype = prototype != null; this.prototype = prototype; if (isConstructor() || isInterface()) { FunctionType superClass = getSuperClassConstructor(); if (superClass != null) { superClass.addSubType(this); } } if (replacedPrototype) { clearCachedValues(); } return true; } /** * Returns all interfaces implemented by a class or its superclass and any * superclasses for any of those interfaces. If this is called before all * types are resolved, it may return an incomplete set. */ public Iterable<ObjectType> getAllImplementedInterfaces() { // Store them in a linked hash set, so that the compile job is // deterministic. Set<ObjectType> interfaces = Sets.newLinkedHashSet(); for (ObjectType type : getImplementedInterfaces()) { addRelatedInterfaces(type, interfaces); } return interfaces; } private void addRelatedInterfaces(ObjectType instance, Set<ObjectType> set) { FunctionType constructor = instance.getConstructor(); if (constructor != null) { if (!constructor.isInterface()) { return; } set.add(instance); if (constructor.getSuperClassConstructor() != null) { addRelatedInterfaces( constructor.getSuperClassConstructor().getInstanceType(), set); } } } /** Returns interfaces implemented directly by a class or its superclass. */ public Iterable<ObjectType> getImplementedInterfaces() { FunctionType superCtor = isConstructor() ? getSuperClassConstructor() : null; if (superCtor == null) { return implementedInterfaces; } else { return Iterables.concat( implementedInterfaces, superCtor.getImplementedInterfaces()); } } public void setImplementedInterfaces(List<ObjectType> implementedInterfaces) {

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS> // Records this type for each implemented interface. for (ObjectType type : implementedInterfaces) { registry.registerTypeImplementingInterface(this, type); } this.implementedInterfaces = ImmutableList.copyOf(implementedInterfaces); } @Override public boolean hasProperty(String name) { return super.hasProperty(name) || "prototype".equals(name); } @Override public boolean hasOwnProperty(String name) { return super.hasOwnProperty(name) || "prototype".equals(name); } @Override public JSType getPropertyType(String name) { if ("prototype".equals(name)) { return getPrototype(); } else { if (!hasOwnProperty(name)) { if ("call".equals(name)) { // Define the "call" function lazily. Node params = getParametersNode(); if (params == null) { // If there's no params array, don't do any type-checking // in this CALL function. defineDeclaredProperty(name, new FunctionBuilder(registry) .withReturnType(getReturnType()) .build(), false, source); } else { params = params.cloneTree(); Node thisTypeNode = Node.newString(Token.NAME, "thisType"); thisTypeNode.setJSType( registry.createOptionalNullableType(getTypeOfThis())); params.addChildToFront(thisTypeNode); thisTypeNode.setOptionalArg(true); defineDeclaredProperty(name, new FunctionBuilder(registry) .withParamsNode(params) .withReturnType(getReturnType()) .build(), false, source); } } else if ("apply".equals(name)) { // Define the "apply" function lazily. FunctionParamBuilder builder = new FunctionParamBuilder(registry); // Ecma-262 says that apply's second argument must be an Array // or an arguments object. We don't model the arguments object, // so let's just be forgiving for now. // TODO(nicksantos): Model the Arguments object. builder.addOptionalParams( registry.createNullableType(getTypeOfThis()), registry.createNullableType( registry.getNativeType(JSTypeNative.OBJECT_TYPE))); defineDeclaredProperty(name, new FunctionBuilder(registry)

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS> .withParams(builder) .withReturnType(getReturnType()) .build(), false, source); } } return super.getPropertyType(name); } } @Override boolean defineProperty(String name, JSType type, boolean inferred, boolean inExterns, Node propertyNode) { if ("prototype".equals(name)) { ObjectType objType = type.toObjectType(); if (objType != null) { if (objType.isEquivalentTo(prototype)) { return true; } return setPrototype( new FunctionPrototypeType( registry, this, objType, isNativeObjectType())); } else { return false; } } return super.defineProperty(name, type, inferred, inExterns, propertyNode); } @Override public boolean isPropertyTypeInferred(String property) { return "prototype".equals(property) || super.isPropertyTypeInferred(property); } @Override public JSType getLeastSupertype(JSType that) { return supAndInfHelper(that, true); } @Override public JSType getGreatestSubtype(JSType that) { return supAndInfHelper(that, false); } /** * Computes the supremum or infimum of functions with other types. * Because sup() and inf() share a lot of logic for functions, we use * a single helper. * @param leastSuper If true, compute the supremum of {@code this} with * {@code that}. Otherwise compute the infimum. * @return The least supertype or greatest subtype. */ private JSType supAndInfHelper(JSType that, boolean leastSuper) { // NOTE(nicksantos): When we remove the unknown type, the function types // form a lattice with the universal constructor at the top of the lattice, // and the LEAST_FUNCTION_TYPE type at the bottom of the lattice. // // When we introduce the unknown type, it's much more difficult to make // heads or tails of the partial ordering of types, because there's no // clear hierarchy between the different components (parameter types and // return types) in the ArrowType. // // Rather than make the situation more complicated by introducing new // types (like unions of

Closure, 74

<FILEB>
<CHANGES>
int lhType = getNormalizedNodeType(left);
int rhType = getNormalizedNodeType(right);
<CHANGEE>
<CHANGES>
private int getNormalizedNodeType(Node n) {
int type = n.getType();
if (type == Token.NOT) {
TernaryValue value = NodeUtil.getPureBooleanValue(n);
switch (value) {
case TRUE:
return Token.TRUE;
case FALSE:
return Token.FALSE;
}
}
return type;
}
<CHANGEE>
<FILEE>
<FILEB> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left, false) || !NodeUtil.isLiteralValue(right, false)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right, false); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild(), false))); <CHANGES> int lhType = left.getType(); int rhType = right.getType(); <CHANGEE> switch (lhType) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) { return n; } else if (!rightLiteral) { return n; } else { result = compareToUndefined(right, op); } break; case Token.NULL: case Token.TRUE: result = false; break; default: return n; // don't handle that op } break; default: // assert, this should cover all consts return n; } Node newNode = new Node(result ? Token.TRUE : Token.FALSE); n.getParent().replaceChild(n, newNode); reportCodeChange(); return newNode; } /** * @return Translate NOT expressions into TRUE or FALSE when possible. */ <CHANGES> <CHANGEE> /** * The result of the comparison as a Boolean or null if the * result could not be determined. */ private Boolean compareAsNumbers(int op, Node left, Node right) { Double leftValue = NodeUtil.getNumberValue(left); if (leftValue == null) { return null; } Double rightValue = NodeUtil.getNumberValue(right); if (rightValue == null) { return null; <FILEE> <SCANS> { if (hasKnownTypeOfThis) { b.append(", "); } Node p = call.parameters.getFirstChild(); b.append(getDebugHashCodeStringOf(p.getJSType())); p = p.getNext(); while (p != null) { b.append(", "); b.append(getDebugHashCodeStringOf(p.getJSType())); p = p.getNext(); } } b.append(")"); b.append(": "); b.append(getDebugHashCodeStringOf(call.returnType)); return b.toString(); } private String getDebugHashCodeStringOf(JSType type) { if (type == this) { return "me"; } else { return type.toDebugHashCodeString(); } } }